如何保證執行緒安全?

2021-09-12 09:02:31 字數 1205 閱讀 1101

執行緒安全

一般說來,確保執行緒安全的方法有這幾個:競爭與原子操作、同步與鎖、可重入、過度優化。

競爭與原子操作

多個執行緒同時訪問和修改乙個資料,可能造成很嚴重的後果。出現嚴重後果的原因是很多操作被作業系統編譯為彙編**之後不止一條指令,因此在執行的時候可能執行了一半就被排程系統打斷了而去執行別的**了。一般將單指令的操作稱為原子的(atomic),因為不管怎樣,單條指令的執行是不會被打斷的。

因此,為了避免出現多執行緒運算元據的出現異常,linux系統提供了一些常用操作的原子指令,確保了執行緒的安全。但是,它們只適用於比較簡單的場合,在複雜的情況下就要選用其他的方法了。

同步與鎖

為了避免多個執行緒同時讀寫乙個資料而產生不可預料的後果,開發人員要將各個執行緒對同乙個資料的訪問同步,也就是說,在乙個執行緒訪問資料未結束的時候,其他執行緒不得對同乙個資料進行訪問。

同步的最常用的方法是使用鎖(lock),它是一種非強制機制,每個執行緒在訪問資料或資源之前首先試圖獲取鎖,並在訪問結束之後釋放鎖;在鎖已經被占用的時候試圖獲取鎖時,執行緒會等待,直到鎖重新可用。

二元訊號量是最簡單的一種鎖,它只有兩種狀態:占用與非占用,它適合只能被唯一乙個執行緒獨佔訪問的資源。對於允許多個執行緒併發訪問的資源,要使用多元訊號量(簡稱訊號量)。

可重入乙個函式被重入,表示這個函式沒有執行完成,但由於外部因素或內部因素,又一次進入該函式執行。乙個函式稱為可重入的,表明該函式被重入之後不會產生任何不良後果。可重入是併發安全的強力保障,乙個可重入的函式可以在多執行緒環境下放心使用。

過度優化

在很多情況下,即使我們合理地使用了鎖,也不一定能夠保證執行緒安全,因此,我們可能對**進行過度的優化以確保執行緒安全。

我們可以使用volatile關鍵字試圖阻止過度優化,它可以做兩件事:第一,阻止編譯器為了提高速度將乙個變數快取到暫存器而不寫回;第二,阻止編譯器調整操作volatile變數的指令順序。

過度優化

在很多情況下,即使我們合理地使用了鎖,也不一定能夠保證執行緒安全,因此,我們可能對**進行過度的優化以確保執行緒安全。

我們可以使用volatile關鍵字試圖阻止過度優化,它可以做兩件事:第一,阻止編譯器為了提高速度將乙個變數快取到暫存器而不寫回;第二,阻止編譯器調整操作volatile變數的指令順序。

在另一種情況下,cpu的亂序執行讓多執行緒安全保障的努力變得很困難,通常的解決辦法是呼叫cpu提供的一條常被稱作barrier的指令,它會阻止cpu將該指令之前的指令交換到barrier之後,反之亦然。

如何保證Java執行緒安全

不要跨執行緒訪問共享變數 使共享變數是final型別的 使共享變數唯讀 將共享變數的操作加上同步 對於volatile宣告的數值型別變數進行運算,往往是不安全的 volatile只能保證可見性,不能保證原子性 使用普通同步容器 vector,hashtable 的迭代器,需要外部鎖來保證其原子性。原...

如何保證ArrayList執行緒安全

一 繼承arraylist,然後重寫或按需求編寫自己的方法,這些方法要寫成synchronized,在這些synchronized的方法中呼叫arraylist的方法。二 使用collections.synchronizedlist 使用方法如下 假如你建立的 如下 list data new ar...

如何保證ArrayList執行緒安全

一 繼承arraylist,然後重寫或按需求編寫自己的方法,這些方法要寫成synchronized,在這些synchronized的方法中呼叫arraylist的方法。二 使用collections.synchronizedlist 使用方法如下 假如你建立的 如下 list data new ar...