天天看點

原子性、可見性和有序性

原子性(Atomicity)

由Java記憶體模型來直接保證的原子性變量操作包括read、load、assign、use、store和write,我們大緻可以認為基本資料類型的通路讀寫是具備原子性的。

Java記憶體模型提供了lock和unlock來保證更大範圍的原子操作,盡管虛拟機未把lock和unlock操作直接開放給使用者使用,但是卻提供了更高層次的位元組碼指令monitorenter和monitorexit來隐式地使用這兩個操作,這兩個位元組碼指令反映到Java代碼中就是同步塊——synchronized關鍵字,是以synchronized塊之間的操作也具備原子性。

可見性(Visibility)

可見性是指當一個線程修改了共享變量的值,其他變量能夠立即得知這個修改。

Java記憶體模型是通過變量修改後将新值同步回主記憶體,在變量讀取前從主記憶體重新整理變量這種依賴主記憶體作為傳遞媒介的方式來實作可見性,無論是普通變量還是volatile變量都是如此。普通變量與volatile變量的差別是,volatile的特殊規則保證了新值能立即同步到主記憶體,以及每次使用前立即從主記憶體重新整理,是以可以說volatile保證了多線程操作時變量的可見性。

同步塊的可見性是由“對一個變量執行unlock之前”,必須先把此變量同步回主記憶體中(執行store、write操作),JMM會把該線程對應的本地記憶體中的共享變量重新整理到記憶體中,是以synchronized保證了可見性。

JMM禁止編譯器把final域的寫重排序到構造函數之外,被final修飾的字段在構造器中一旦初始化完成,并且構造器沒有把“this”的引用傳遞出去,那麼其他線程就能看見final字段的值,是以final保證了可見性。

有序性(Ordering)

Java程式中天然都有序性可以總結為一句話:如果在本線程内觀察,所有操作都是有序的;如果在一個線程中觀察另一個線程,所有操作都是無序的。前半句是指“線程内表現為串行的語義”,後半句是指“指令重排序”現象和“工作記憶體與主記憶體同步延遲”現象。

Java提供了volatile和synchronized兩個關鍵字來保證線程之間操作的有序性,volatile禁止重排序,synchronized則由“一個變量在同一時刻隻允許一條線程對其進行lock操作”這條規則獲得的,這條規則決定了持有同一個鎖的兩個同步塊隻能串行地進入。

總結

關鍵字 具有特性
synchronized 原子性、可見性、有序性
volatile 可見性、有序性。
final 可見性。

繼續閱讀