一. 關於server模式下的主存和工做內存
規則40 多線程訪問同一個可變變量,需增長同步機制
說明:根據Java Language Specification中對Java內存模型的定義, JVM中存在一個主內存(Java Heap Memory),Java中全部變量都儲存在主存中,對於全部線程都是共享的。每一個線程都有本身的工做內存(Working Memory),工做內存中保存的是主存中某些變量的拷貝,線程對全部變量的操做都是在工做內存中進行,線程之間沒法相互直接訪問,變量傳遞均須要經過主存完成。根據上述內存模型的定義,要在多個線程間安全的同步共享數據就必須使用鎖機制,將某線程中更新的數據從其工做內存中刷新至主內存,並確保其餘線程從主內存獲取此數據更新後的值再使用。
示例:
很差:下面的代碼中,沒有對可變數據stopRequested的訪問作同步。程序指望在一秒鐘後線程能中止。但在用java 1.6的server模式運行此程序(Java –server StopThread)時,程序陷入死循環,不能結束。
public class StopThread
{
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException
{
Thread backgroundThread = new Thread(new Runnable()
{
public void run()
{
int i = 0;
while (!stopRequested)
{
i++;
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
這裏爲何會陷入死循環,永遠不會中止呢?
參考兩篇文章
http://m.blog.csdn.net/blog/lyy5682077/17588155
http://www.cnblogs.com/trytocatch/archive/2013/01/07/2850002.html
JIT或HotSpot編譯器在server模式和client模式編譯不一樣,server模式爲了使線程運行更快,若是其中一個線程更改了變量boolean flag 的值,那麼另一個線程會看不到,由於另一個線程爲了使得運行更快因此從寄存器或者本地cache中取值,而不是從內存中取值,那麼使用volatile後,就告訴不管是什麼線程,被volatile修飾的變量都要從內存中取值。《內存柵欄》
java在server模式下,各個線程使用各自的工做內存,一個線程改變了變量的值,另一個線程並不會從主存中取
上面例子中的問題,變量
stopRequested前加上volatile能夠解決:
增長了
synchronized
同步機制後,程序就能正確地在
1
秒後終止。另外一個方案是在變量前增長
volatile
關鍵字。
public class StopThread
{
private static boolean stopRequested;
private static synchronized void requestStop()
{
stopRequested = true;
}
private static synchronized boolean isStopRequested()
{
return stopRequested;
}
public static void main(String[] args) throws InterruptedException
{
Thread backgroundThread = new Thread(new Runnable()
{
public void run()
{
int i = 0;
while (!isStopRequested())
{
i++;
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
二. static和volatile的區別
參考http://blog.sina.com.cn/s/blog_4e1e357d0101i486.html
1. volatile是告訴編譯器,每次取這個變量的值都須要從主存中取,而不是用本身線程工做內存中的緩存.
2. static 是說這個變量,在主存中全部此類的實例用的是同一份,各個線程建立時須要從主存同一個位置拷貝到本身工做內存中去(而不是拷貝此類不一樣實例中的這個變量的值),也就是說只能保證線程建立時,變量的值是相同來源的,運行時仍是使用各自工做內存中的值,依然會有不一樣步的問題.