java併發程式設計實戰 物件的共享

2021-07-11 19:11:23 字數 2384 閱讀 8983

一、可見性

當讀操作和寫操作在不同的執行緒進行的時候,並不能保證讀的執行緒可以讀到寫執行緒最新的更改。如果要確保記憶體對寫入操作的可見性,就必須使用同步。

處理器還會對程式中的操作進行重排序。重排序保證在單執行緒的執**況下,和不重排序得到的結果一樣,但是多執行緒的話,就不一定了。

乙個簡單的方法避免所有的問題就是:只要有資料共享,就是用正確的同步。

1.失效資料    看下面的程式:

如果不對set和get進行同步,肯定是不能保證可見性的。但是僅對set加鎖,仍然可能會看到失效的資料。因為set同步後把資料重新整理到主記憶體,但是get的時候,還是使用的工作記憶體,並沒有去主記憶體取值。

2.volatile變數

volatile是一種弱同步機制,可以保證可見性,但是不能保證原子性。

volatile變數的正確使用方式是:

當且僅當滿足以下條件時,才可以使用volatile變數

二、發布和溢位

發布就是使物件能夠在當前的作用域之外的**中使用。在乙個非私有(非private和final方法)的方法中返回該引用,或者將物件引用儲存到其他**可以訪問到的地方。

發布狀態最簡單的方法就是:將物件引用儲存到共有的靜態變數中。public static setaset;

發布物件之後,不知道外部**會對物件做什麼操作,所以勿用該物件的風險一直存在。

2.安全的物件構造過程

不要在構造過程中使this引用逸出。比如在構造過程中啟動乙個執行緒。就是,建構函式中,不要使用this的相關引用。

三、執行緒封閉

一種避免使用同步的方式,就是不共享資料。如果僅在單執行緒內訪問資料,就不需要同步。這種技術稱為執行緒封閉。三種方式:ad-hoc,棧封閉,threadlocal。

1.棧封閉

在維持物件引用的封閉性時,比如上面的animals物件,要確保棧封閉性,就要確保animals不會被發布到外面去。那麼這段**也是棧封閉的。

3.threadlocal類

threadlocal常用與防止對可變的單例項變數或全域性變數進行共享。當某個頻繁的操作需要乙個臨時物件,比如說緩衝區,而同時又希望避免在每次執行時,都重新分配該臨時物件,就可以使用這種技術。

threadlocal類類似於全部變數會,降低**的可重用性。

四、不變性

如果某個物件建立後,其狀態就不能修改,我們稱之為不可變物件。不可變物件一定是執行緒安全的。

當滿足以下條件時,物件才是可變的:

不可變的物件並不是不可變的物件引用。

2.final域

final型別的域中可以儲存對可變物件的引用。final域能夠確保初始化過程的安全性,從而可以不受限制的訪問不可變物件,並在共享這些物件時,不需要使用同步。

除非需要某個域是可變的,否則應該將其宣告為final域,是乙個比較好的程式設計習慣。

當訪問和更新多個相關變數時出現競態條件,可以通過把這些變數都儲存在乙個不可變物件中來消除。

當需要更新這個變數的時候,在重新new乙個不可變物件就好了。

五、安全發布

1.不正確的發布:正確的物件被破壞

在物件被完全構造出來之前,將其發不出去。

2.不可變物件與初始化安全性

我們知道:即使某個物件的引用對其他執行緒來說是可見的,也不意味著物件狀態對於該執行緒一定是可見的。為了使物件狀態呈現出一致性檢視,必須使用同步。

即使再發布不可變物件時,沒有使用同步,也可以保證這種可見性。可以延伸到final型別的域中。

3.安全閥不得常用模式

4.實事不可變物件

如果物件從技術上來說是可變的,但是從它發布以後,就不再改變。這種物件稱為事實不可變物件。不需要額外同步的情況下,任何執行緒都可以安全的訪問實事不可變物件。

5.可變物件

要安全的共享可變物件,這些物件就必須被安全的發布,並且必須是執行緒安全或者某個鎖保護起來。

物件的發布需求取決於它的可變性:

不可變物件可通過任意機制發布。

實事不可變物件必須通過安全方式發布。

物件就必須被安全的發布,並且必須是執行緒安全或者某個鎖保護起來

可變。

6.安全的共享物件

當發布乙個物件的時候,必須明確地說明物件的訪問方式。

執行緒封閉

唯讀共享

執行緒安全共享

保護物件。

Java併發程式設計實戰 總結

1.可變狀態是至關重要的。所有的併發問題都可以歸結為如何協調對併發狀態的訪問,可變狀態越少,就越容易確保執行緒安全性。2.盡量將域宣告為final型別,除非需要它們是可變的。3.不可變物件一定是執行緒安全的。不可變物件能極大地降低併發程式設計的複雜性。它們更為簡單而且安全,可以任意共享而無須使用加鎖...

java併發程式設計實戰 簡介

1 併發和並行的區別 併發 多個程式在同一時間段執行,只有乙個cpu。並行 多個程式在同一時刻執行,有多個cpu。2 執行緒帶來的風險 1 安全性問題 永遠不發生糟糕的事情 兩個或多個執行緒同時訪問乙個變數,可能會出現差錯。例如,兩個執行緒同時對乙個變數執行讀操作,從而它們得到了相同的值,違背了該變...

《Java併發程式設計實戰》 5

每當看到new thread runnable start 時,並且你希望獲得一種更靈活的執行策略時,請考慮使用excecutor來代替thread。completionservice將execute和blockingqueue的功能融合在一起。executorcompletionservice實現...