非線程安全主要是指多個線程對同一個對象的實例變量進行操作時,會出現值被更改,值不同步的情況。
線程安全問題表現為三個方面: 原子性,可見性和有序性。
原子(Atomic)就是不可分割的意思. 原子操作的不可分割有兩層含義:
● 訪問(讀,寫)某個共享變量的操作從其他線程來看,該操作要么已經執行完畢,要么尚未發生, 即其他線程年示到當前操作的中間結果。
● 訪問同一組共享變量的原子操作是不能夠交錯的。
如現實生活中從ATM機取款, 對于用戶來說,要么操作成功,用戶拿到錢, 余額減少了,增加了一條交易記錄; 要么沒拿到錢,相當于取款操作沒有發生。
Java有兩種方式實現原子性:
一種是使用鎖; 另一種利用處理器的CAS(Compare and Swap)指令。
鎖具有排它性,保證共享變量在某一時刻只能被一個線程訪問。
CAS指令直接在硬件(處理器和內存)層次上實現,看作是硬件鎖。
在多線程環境中, 一個線程對某個共享變量進行更新之后 , 后續其他的線程可能無法立即讀到這個更新的結果, 這就是線程安全問題的另外一種形式: 可見性(visibility)。
如果一個線程對共享變量更新后, 后續訪問該變量的其他線程可以讀到更新的結果, 稱這個線程對共享變量的更新對其他線程可見, 否則稱這個線程對共享變量的更新對其他線程不可見。
多線程程序因為可見性問題可能會導致其他線程讀取到了舊數據(臟數據)。