volatile和synchronized的區別

volatile和synchronized特色

首先須要理解線程安全的兩個方面:執行控制內存可見html

執行控制的目的是控制代碼執行(順序)及是否能夠併發執行。緩存

內存可見控制的是線程執行結果在內存中對其它線程的可見性。根據Java內存模型的實現,線程在具體執行時,會先拷貝主存數據到線程本地(CPU緩存),操做完成後再把結果從線程本地刷到主存。安全

synchronized關鍵字解決的是執行控制的問題,它會阻止其它線程獲取當前對象的監控鎖,這樣就使得當前對象中被synchronized關鍵字保護的代碼塊沒法被其它線程訪問,也就沒法併發執行。更重要的是,synchronized還會建立一個內存屏障,內存屏障指令保證了全部CPU操做結果都會直接刷到主存中,從而保證了操做的內存可見性,同時也使得先得到這個鎖的線程的全部操做,都happens-before於隨後得到這個鎖的線程的操做。markdown

volatile關鍵字解決的是內存可見性的問題,會使得全部對volatile變量的讀寫都會直接刷到主存,即保證了變量的可見性。這樣就能知足一些對變量可見性有要求而對讀取順序沒有要求的需求。併發

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

在Java 5提供了原子數據類型atomic wrapper classes,對它們的increase之類的操做都是原子操做,不須要使用sychronized關鍵字。jvm

對於volatile關鍵字,當且僅當知足如下全部條件時可以使用:post

1. 對變量的寫入操做不依賴變量的當前值,或者你能確保只有單個線程更新變量的值。
2. 該變量沒有包含在具備其餘變量的不變式中。優化

 

volatile和synchronized的區別

  • volatile本質是在告訴jvm當前變量在寄存器(工做內存)中的值是不肯定的,須要從主存中讀取; synchronized則是鎖定當前變量,只有當前線程能夠訪問該變量,其餘線程被阻塞住。
  • volatile僅能使用在變量級別;synchronized則可使用在變量、方法、和類級別的
  • volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則能夠保證變量的修改可見性和原子性
  • volatile不會形成線程的阻塞;synchronized可能會形成線程的阻塞。
  • volatile標記的變量不會被編譯器優化;synchronized標記的變量能夠被編譯器優化
相關文章
相關標籤/搜索