對象的共享——《Java併發編程實戰》學習筆記二

    倘若synchronize只能用於實現原子性或確定臨界區(Critical Section)。那麼線程A修改了某個共享參數後,線程B可能獲取到的參數不是最新的,同樣會出現問題。因此,同步還有另外一個重要方面:內存可見性(Memory Visibility)。

    爲了保證多個線程間對內存寫入操作的可見性,必須使用同步機制。

    1、失效數據:共享數據在多個線程下,缺乏同步時,2個共享數據可能出現4種不同的複雜情況。但是,這個失效值是由之前某個線程設置的值,而不是一個隨機值。這種稱爲最低安全性(out-of-thin-airsafety)。

    2、非原子的64位操作:最低安全性適用於大多數變量。但是非volatile的64位數值變量(double和long)。Java內存模型要求,變量的讀取和寫入操作必須是原子操作,但對於非volatile類型的long和double變量,JVM會分解爲兩個32位的操作。針對64位變量的讀寫操作在不同線程中執行,那麼就可能讀取到某個值得高32位,另一個值得低32位。

    因此,針對共享的和可變的狀態操作時,需要使用同步機制保護。

    3、加鎖和可見性:核心是鎖的happends-before原則,同一個鎖的unlock操作happend-before鎖的lock操作。例:A、B線程先後進入由同一個鎖保護的同步代碼塊時,當B執行由鎖保護的同步代碼塊時,可以看到A之前在同一個代碼塊中的所有操作結果。注意單例中的DCL。

    4、volatile和可見性:核心是volatile的happends-before原則,對一個volatile變量的寫操作happend-before此變量的任意操作(包括寫操作)。例:線程A、B依次寫入和讀取volatile變量,在寫入volatile變量之前對A可見的所有變量的值,在B讀取volatile變量後,對B都是可見的。因此,從內存可見性角度來看,寫入volatile變量相當於退出同步代碼塊,而讀取volatile變量相當於進入同步代碼塊。

    因此,加鎖機制確保可見性和原子性,而volatile變量只能確保可見性。

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