從零開始學多執行緒之共享物件 二

2021-09-05 10:19:43 字數 2628 閱讀 3881

想要使用多執行緒程式設計,有乙個很重要的前提,那就是必須保證操縱的是執行緒安全的類.

那麼如何構建執行緒安全的類呢? 1. 使用同步來避免多個執行緒在同一時間訪問同一資料. 2. 正確的共享和安全的發布物件,使多個執行緒能夠安全的訪問它們.

那麼如何正確的共享和安全的發布物件呢? 這正是這篇部落格要告訴你的.

多執行緒之間的可見性問題.

為什麼在多執行緒條件下需要正確的共享和安全的發布物件呢?

這要說到可見性的問題:

在多執行緒環境下,不能保證乙個執行緒修改完共享物件的資料,對另乙個執行緒是可見的.

乙個執行緒讀到的資料也許是乙個過期資料,這會導致嚴重且混亂的問題,比如意外的異常,髒的資料結構,錯誤的計算和無限的迴圈.

舉個例子:

public class novisibility

system.out.println("num = " + num);

}}public static void main(string args) throws interruptedexception new renderthread().start()表示建立乙個新執行緒,並執行執行緒內的run()方法 ,如果ready的值是false,執行thread.yield()方法(當前執行緒休息一會讓其他執行緒執行),這時候再交給main方法的主線程執行,給num賦值42,ready賦值true,然後在任務執行緒中輸出num的值.因為可見性的問題,任務執行緒可能沒有看到主線程對num賦值,而輸出0.

我們接下來來看看發布物件也會引發的可見性問題.

什麼是發布乙個物件

發布: 讓物件內被當前範圍之外的**所使用.

public class publish 無論是 publish.num1 還是 publish.getnum2()哪種方法,只要能在類以外的地方獲取到物件,我們就稱物件被發布了.

如果乙個物件在沒有完成構造的情況下就發布了,這種情況叫逸出.逸出會導致其他執行緒看到過期值,危害執行緒安全.

常見的逸出的情況:

1.最常見的逸出就是將物件的引用放到公共靜態域(public static object obj),發布物件的引用,而在區域性方法中例項化這個物件.

public class test 2.發布物件的狀態,而且狀態是可變的(沒用final修飾),或狀態裡包含其他的可變資料.

public class unsafestates ;

public string getstates()
3.在構造方法中使用內部類. 內部類的例項包含了對封裝實隱含的引用.

public class unsafestates

};}逸出主要會導致兩個方面的問題:

發布執行緒以外的任何執行緒都能看到物件的域的過期值,因而看到的是乙個null引用或者舊值,即使此刻物件已經被賦予了新值.

執行緒看到物件的引用是最新的,但是物件的狀態卻是過期的.

我們已經了解了逸出的問題,那麼如何安全的發布乙個物件呢?

為了安全地發布物件,物件的引用以及物件的狀態必須同時對其他執行緒可見(也就是說安全發布就是保證物件的可見性),乙個正確建立的物件可以通過下列條件安全發布:

通過靜態初始化器初始化物件的引用.

public class novisibility

}public void changecondition()else

}將它的引用儲存到正確建立的物件的final域中.

public class novisibility }

不限於hashtable,只要是執行緒安全的容器都行

現在我們了解了如何安全的發布乙個物件,那麼

問題來了,是否所有物件都需要安全發布?安全發布的物件是否就是執行緒全的了?

讓我們繼續往下看.

3.如何構建乙個執行緒安全的類.

我們先來回答上面的第乙個疑問,是否所有物件都需要安全發布?

答案都是否定的.

要回答這個問題,我們先簡單了解一下以下的三種物件:

1.不可變物件

2.高效不可變物件

3.可變物件

1.不可變物件:建立後不能被修改的物件叫不可變物件,不可變物件天生是執行緒安全的.

不可變物件不僅僅是所有域都是final型別的,

只有滿足如下狀態才是不可變物件:

1.1它的狀態不能在建立後改變.(包括狀態包含的其他值也不可做修改,比如狀態是乙個集合list,list裡面的值也不可以修改,或者狀態是乙個物件,那麼物件的狀態也不更改)

1.2.所有域都是final型別的.

1.3.它被正確建立(建立期間沒有this引用的逸出)

2.不可變物件: 技術上是可以改變的,但是實際應用程式中,不會被改變

用高效不可變物件可以簡化開發,並由於減少了同步的使用,還會提高效能.

可變物件: 就是可變物件.

下面就是三種物件的發布機制,發布物件的必要條件依賴於物件的可變性:

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

高效不可變物件必須要安全地發布;

可變物件必須要安全發布,同時必須要執行緒安全或者是被鎖保護.

最後乙個問題安全發布的物件是否就是執行緒全的了?

安全發布只能保證物件發布時的可見性,所以要保證執行緒的安全就要根據物件的可變性,通過同步+安全發布來保證執行緒安全.

從零開始學C 基本語法(二)

菜鳥系列學習教程 c 又名csharp,喜歡叫c井。c 是一種物件導向的程式語言。在物件導向的程式設計方法中,程式有各種相互互動的物件組成。相同種類的物件通常具有相同的型別,或者說,是在先溝通那個的class中。例如,以rectangle 矩形 物件為例,它具有length和width屬性。根據設計...

從零開始學領域驅動設計 二

我覺得這個需要從業務的角度深入分析哪些物件它們的關係是內聚的,即我們會把他們看成是乙個整體來考慮的 然後這些物件我們就可以把它們放在乙個聚合內。所謂關係是內聚的,是指這些物件之間必須保持乙個固定規則,固定規則是指在資料變化時必須保持不變的一致性規則。當我們在修改乙個聚合時,我們必須在事務級別確保整個...

從零開始學python 二,資料型別

python中的數型別分為4種 整數,長整數,浮點型以及複數 而python中的字串可以有很多種表示方式 單引號和雙引號 沒有任何區別 三引號 被三引號包裹的字串裡可以隨意使用 單引號和 雙引號 自然字串 字串開頭使用r或者r 自動忽略字串裡的轉譯字元 如 r my name is zhangxia...