volatile不保證原子性

qq_30035749發表於2019-03-13

我的理解是,在volatile單獨的讀和寫,都是直接從主記憶體中讀,寫入主記憶體,但是,在volatile i++的時候,另外一個執行緒假設已經改變了i的值,並寫入主記憶體,並告訴其他執行緒你們快取的資料已經失效了,但是本執行緒已經完成i++,並且不需要再讀取i的值,我現在要做的事情是寫i。所以我不會再去讀取i的最新值。volatile保證的是,在讀的時候會從主存中讀,在寫的時候寫入主存。
在生成彙編程式碼時會在volatile修飾的共享變數進行寫操作的時候會多出Lock字首的指令

  • Lock字首的指令會引起處理器快取寫回記憶體;
  • 一個處理器的快取回寫到記憶體會導致其他處理器的快取失效;
  • 當處理器發現本地快取失效後,就會從記憶體中重讀該變數資料,即可以獲取當前最新值。
    記憶體屏障(memory barrier)是一個CPU指令。基本上,它是這樣一條指令: a) 確保一些特定操作執行的順序; b) 影響一些資料的可見性(可能是某些指令執行後的結果)。編譯器和CPU可以在保證輸出結果一樣的情況下對指令重排序,使效能得到優化。插入一個記憶體屏障,相當於告訴CPU和編譯器先於這個命令的必須先執行,後於這個命令的必須後執行。記憶體屏障另一個作用是強制更新一次不同CPU的快取。例如,一個寫屏障會把這個屏障前寫入的資料重新整理到快取,這樣任何試圖讀取該資料的執行緒將得到最新值,而不用考慮到底是被哪個cpu核心或者哪個CPU執行的。
    如果讓volatile滿足原子性:
    1.運算結果並不依賴於變數當前的值,,或者確保只有一個執行緒改變數的值;
    2.變數不需要與其他變數共同參與不變約束;

synchronized 是原子的,lock 和unlock指令是原子的,雖然jvm沒有開放給程式設計師使用,但是更高層指令monitorenter和monitorexit指令開放給程式設計師使用,反映到java程式碼中就是synchronized關鍵字。synchronized具有有序性,要求執行緒訪問共享變數時只能“序列“執行
volatile具有有序性,包含禁止指令重排序的語義,其具有有序性;
synchronized具有可見性,獲得鎖時會從主存中獲取最新值,釋放鎖時會將共享變數同步到主存中。
總結:synchronized具有有序性、原子性、可見性,volatile具體有序性、可見性。

相關文章