天天看點

java并發程式設計實踐之對象的共享

3.1.可見性

synchronized除了用于操作的原子性之外,還有更加重要的作用,可見性。記憶體可見性:當某個線程修改某狀态時,其他線程不要讀寫或者修改該狀态,并且當線程修改好狀态後,其他線程都能在記憶體中看到該狀态的改變。

java并發程式設計實踐之對象的共享

圖一

如果并發正确的話,主線程啟動讀線程,主線程對number,ready指派後,讀線程讀到ready=true,并最後列印出number=42;但是并發錯誤的話,可能會列印出number=0或者一直循環,無法終止。ready和number都是類變量,在類加載的準備階段都是初始化成0,在類加載的初始化階段才被指派成程式員想要的效果,但是jvm會對指令進行優化重排序,可能先執行ready=true;但在還沒有執行number=42時,讀線程已經執行完while語句,列印number的值,那肯定是0了。

3. 1.1 失效資料

競态條件裡

.if(A)
.     then B
           

在執行完語句1,還沒有執行語句2時,語句1的狀态發生改變,那麼A就是一個失效資料了。

3.1.2 加鎖與可見性

内置鎖可以用于確定某個線程以一種可預測的方式來檢視另一個線程的執行結果。

java并發程式設計實踐之對象的共享

線程A,B使用同一把鎖,線程A的同步代碼塊操作先于線程B的同步代碼塊操作,那麼線程A操作的結果線上程B拿到同一把對象鎖之後都可以看到,比如,線程B可以看到x=1;

3.1.3 volatile變量

volatile工作原理:每個線程都有一個私有的工作記憶體,線程可以共享主存,volatile變量被存放在主存裡面,如果線程A從記憶體中讀取并修改了volatile變量,那麼這個變量要被存儲到主存中去,其他線程想要讀寫該變量都要重新到主存裡面去擷取該變量。也就是volatile變量不想其他普通變量一樣,可以被緩存到線程的私有工作記憶體裡面,每次讀寫volatile變量,都要重新倒記憶體中去拿。

volatile變量對可見性的影響比volatile變量本身更加重要。當線程A首先寫入一個volatile變量,線程B随後讀取該volatile變量,再寫入volatile變量之前對線程A可見的所有變量的值,線上程B讀取了volatile變量後,對B也是可見的。是以,從記憶體的角度來看,寫入volatile變量相當于撤出同步代碼塊。

加鎖機制既能確定可見性又能確定原子性,但是volatile隻能確定可見性。當且僅當滿足以下所有條件時,才會使用volatile變量:

  • 當變量的寫入操作不依賴變量的目前值,或者你能確定隻有單個線程能修改變量。
  • 該變量不會和其他變量一起納入不變性條件。
  • 該變量沒有加鎖。

3.2 釋出與逸出

釋出:對象可以被其他線程和對象使用;

逸出:對象還沒有正确建立就被其他線程看見,但對于逸出要防止構造函數中this引用的逸出,比如構造函數中新建立并啟動一個線程,那麼新線程就會将this引用逸出。構造函數可以建立線程,但start或者initialize不能再構造函數裡面。

有個部落格寫的比較好,附上供大家參考[http://www.cnblogs.com/wufengtinghai/p/5260357.html]

3.3 線程封閉