併發內存模型和volatile

       在多線程環境中,我們需要考慮的主要問題是:線程之間如何進行通信,在命令式編程中,線程之間的通信機制有兩種:共享內存和消息傳遞。在共享內存的併發模型裏,線程之間共享程序的公共狀態,線程之間通過寫-讀內存中的公共狀態來隱式進行通信。在消息傳遞的併發模型裏,線程之間沒有公共狀態,線程之間必須通過明確的發送消息來顯式進行通信。Java的併發採用的是共享內存模型,Java線程之間的通信總是隱式進行,整個通信過程對程序員完全透明。

Java內存模型的抽象

       在java中,所有實例域、靜態域和數組元素存儲在堆內存中,堆內存在線程之間共享(本文使用“共享變量”這個術語代指實例域,靜態域和數組元素)。局部變量(Local variables),方法定義參數(java語言規範稱之爲formal method parameters)和異常處理器參數(exception handler parameters)不會在線程之間共享,它們不會有內存可見性問題,也不受內存模型的影響。

       Java線程之間的通信由Java內存模型(本文簡稱爲JMM)控制,JMM決定一個線程對共享變量的寫入何時對另一個線程可見。從抽象的角度來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(main memory)中,每個線程都有一個私有的本地內存(local memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存,寫緩衝區,寄存器以及其他的硬件和編譯器優化。Java內存模型的抽象示意圖如下:


從上圖來看,線程A與線程B之間如要通信的話,必須要經歷下面2個步驟:

1. 首先,線程A把本地內存A中更新過的共享變量刷新到主內存中去。

2. 然後,線程B到主內存中去讀取線程A之前已更新過的共享變量。

下面通過示意圖來說明這兩個步驟:


      如上圖所示,本地內存A和B有主內存中共享變量x的副本。假設初始時,這三個內存中的x值都爲0。線程A在執行時,把更新後的x值(假設值爲1)臨時存放在自己的本地內存A中。當線程A和線程B需要通信時,線程A首先會把自己本地內存中修改後的x值刷新到主內存中,此時主內存中的x值變爲了1。隨後,線程B到主內存中去讀取線程A更新後的x值,此時線程B的本地內存的x值也變爲了1。

       從整體來看,這兩個步驟實質上是線程A在向線程B發送消息,而且這個通信過程必須要經過主內存。JMM通過控制主內存與每個線程的本地內存之間的交互,來爲java程序員提供內存可見性保證。

如何保證內存的可見性?

1、使用synchronized關鍵字

     Java內存模型對Synchronized語義做了以下保證:

       當ThreadA釋放鎖M時,它所寫過的變量(比如,x和y,存在它工作內存中的)都會同步到主存中,而當ThreadB在申請同一個鎖M時,ThreadB的工作內存會被設置爲無效,然後ThreadB會重新從主存中加載它要訪問的變量到它的工作內存中(這時x=1,y=1,是ThreadA中修改過的最新的值)。通過這樣的方式來保證內存的可見性。

2、使用volatile字

       在保證內存可見性這一方面,Synchronizedvolatile沒有很大的區別,volatile實現內存可見性的核心機制是當一個線程修改了一個volatile修飾的變量的值時,該值會被寫入主內存(即RAM)而不僅僅是當前線程所在的CPU的緩存區,而其他CPU的緩存區中存儲的該變量的值也會因此而失效(從而得以更新爲主內存中的該變量的相應值)。

3、Synchronizedvolatile的區別

     那麼既然Synchronizedvolatile都可以保證內存的可見性,那爲何會創造出兩個關鍵字呢?自然是因爲他們之間還有很多不同的地方。

(1)使用條件不同:volatile僅能使用在變量級別;synchronized則可以使用在變量、方法、和類級別的 

(2)造成影響不同:volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞。 

(3)發揮作用不同:Synchronizedvolatile都可以保證內存的可見性,但是Synchronized可以保證操作的原子性,而volatile不可以。

(4)運行過程不同:volatile標記的變量不會被編譯器優化;synchronized標記的變量可以被編譯器優化。

  注:編譯器優化是指編譯器和CPU爲了提高指令的執行效率可能會進行指令重排序,這使得代碼的實際執行方式可能不是按照我們   所認爲的方式進行。

參考文獻:http://www.jianshu.com/p/977d27852826

                    http://www.infoq.com/cn/articles/java-memory-model-1

                






            </div>
                </div>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章