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