volatile和synchronized比較以及線程安全中的應用

一、線程安全的執行控制和內存可見的理解
線程安全的兩個方面:執行控制內存可見
執行控制的目的是控制代碼執行(順序)及是否可以併發執行。
內存可見控制的是線程執行結果在內存中對其它線程的可見性。根據Java內存模型的實現,線程在具體執行時,會先拷貝主存數據到線程本地(CPU緩存),操作完成後再把結果從線程本地刷到主存。

二、synchronized和volatile基本原理
synchronized保證了執行控制,它會阻止其他線程獲取當前對象的監控鎖,這樣就保證了被synchronized保護的代碼其他線程無法訪問。同時它也保證了內存可見,因爲它會創建內存屏障,保證cpu所有的操作結果直接刷入主內存,並happens-before隨後獲取這個鎖的線程的操作(保證當前線程在釋放鎖之前操作的完成性)。
volatile則保證了內存可見,保證所有讀寫操作都會直接發生在主內存中,但是它不保證讀取順序,也不能保證多個線程操作同一個變量的線程安全,只能保證多個線程操作的是同一塊主內存。

三、volatile關鍵字使用場景
對於volatile關鍵字,當且僅當滿足以下所有條件時可使用:
1. 對變量的寫入操作不依賴變量的當前值,或者你能確保只有單個線程更新變量的值。
2. 該變量沒有包含在具有其他變量的不變式中。

四、volatile的侷限性
使用volatile關鍵字僅能實現對原始變量(如boolen、 short 、int 、long等)操作的原子性,但需要特別注意, volatile不能保證複合操作的原子性,即使只是i++,實際上也是由多個原子操作組成:read i; inc; write i,假如多個線程同時執行i++,volatile只能保證他們操作的i是同一塊內存,但依然可能出現寫入髒數據的情況。

五、volatile和synchronized的區別
1、volatile本質是在告訴jvm當前變量在寄存器(工作內存)中的值是不確定的,需要從主存中讀取; synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住。
2、volatile僅能使用在變量級別;synchronized則可以使用在變量、方法、和類級別。
3、volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性。
4、volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞。
5、volatile標記的變量不會被編譯器優化;synchronized標記的變量可以被編譯器優化
延伸:
java5之後提供原子操作類,如AtomicInteger、AtomicLong、AtomicBoolean、AtomicReference,對它們進行操作就不需要使用synchronized關鍵字了。
發佈了38 篇原創文章 · 獲贊 16 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章