多線程中對static和volatile的理解


問題來源於編碼規范的一個例子


一. 關於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 是說這個變量,在主存中所有此類的實例用的是同一份,各個線程創建時需要從主存同一個位置拷貝到自己工作內存中去(而不是拷貝此類不同實例中的這個變量的值),也就是說只能保證線程創建時,變量的值是相同來源的,運行時還是使用各自工作內存中的值,依然會有不同步的問題.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM