[英]Why no volatile?
我和同事討論了這段代碼:
public final class ShutdownHookRegistration {
/**
* Global shutdown flag
*/
private static boolean isServerShutdown = false;
private ShutdownHookRegistration() {
// empty
}
/**
* Returns the current value of the global shutdown flag
*
* @return
*/
public static boolean isServerShutdown() {
return isServerShutdown;
}
/**
* Registration if shutdown hooks
*/
public static void registerShutdownHooks() {
/**
* 1. Shutdown hook to set the shutdown flag
*/
Runtime.getRuntime().addShutdownHook(setGlobalShutdownFlag());
}
/**
* Sets the global static is shutdown flag which can be checked by other processes.
*
* @return
*/
private static Thread setGlobalShutdownFlag() {
return new Thread() {
@Override
public void run() {
isServerShutdown = true;
System.out.println(Thread.currentThread().getName() + ":shutdown set");
}
};
}
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " Flag set:" + ShutdownHookRegistration.isServerShutdown);
Thread t1 = ShutdownHookRegistration.setGlobalShutdownFlag();
Thread t2 = new Thread() {
public void run() {
while (!ShutdownHookRegistration.isServerShutdown) {
System.out.println(Thread.currentThread().getName() + " Flag set:" + ShutdownHookRegistration.isServerShutdown);
}
}
};
t2.start();
t1.start();
}
輸出:
Thread-1 Flag set:false
Thread-1 Flag set:false
Thread-1 Flag set:false
Thread-1 Flag set:false
[..]
Thread-0:shutdown set
我認為沒有volatile這段代碼會在無限循環中運行,但不知怎的,它總會終止。
有人可以解釋為什么這里沒有必要的波動?
簡而言之,有兩個原因,你的循環有一個內存屏障,即使它沒有,它的運行時間也不足以在需要volatile的情況下進行優化/編譯。
關鍵在這里
while (!ShutdownHookRegistration.isServerShutdown) {
System.out.println(Thread.currentThread().getName() + " Flag set:" + ShutdownHookRegistration.isServerShutdown);
}
System.out.println是synchronized
,這意味着每次迭代都有一個讀/寫屏障。
// from the java 6 source
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
在x64 JVM中,一旦鎖定了一個對象,就會放置一個內存屏障來保護所有內存訪問。
此外,這會使代碼速度減慢10,000倍或更多,因此運行時間不足以進行編譯(並在需要使用volatile
的情況下進行優化)在編譯此代碼之前,需要循環10,000次。 。
每個線程都獲得變量isServerShutdown的副本,JVM可以在每個未確定的時間刷新並更新該值,許多應用程序將工作,許多不,其他人將在run方法中添加另一個語句時工作...
你很幸運,如果你需要應用程序工作,你應該使用揮發性變量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.