java併發和高併發之線程安全性——可見性

一、可見性:

1、定義:線程對主內存的修改可以及時地被其他線程觀察到;

2、導致共享變量在線程間不可見的可能性原因:

》線程交叉執行;

》重排序結合線程交叉執行;

》共享變量更新後的值沒有在工作內存與主存間及時刷新;

3、不同解決方案對可見性的處理:

1)可見性——synchronized

JMM 關於synchronized的兩條規定:

》線程解鎖前,必須把共享變量的最新值刷新到主內存;

》線程加鎖時,將清空工作內存中共享變量的值,從而使用共享變量是需要從主內存中重新讀取最新的值(注意,加鎖與解鎖是同一把鎖)

  原子性演示時,修飾的對象不同時,是互相不影響的。

2)可見性——volatile:

通過加入內存屏障和禁止重排序優化來實現,這種機制實現在CPU的指令層面,。

》對volatile變量寫操作時,會在寫操作後加入一條store屏障指令,將本地內存中的共享變量值刷新到主內存;

》對volatile變量讀操作時,會在讀操作前加入一條load屏障指令,從主內存中讀取共享變量;

4、實例測試:

如果使用volatile修飾之前的計數器的值,是否可以獲取正確的結果呢?

 

運行結果:

如上多次運行可發現,即使上方用volatile修飾,但是仍然無法保證結果,爲什麼呢?

因爲add 方法中,實際執行了三步,在多個線程中執行時,出現問題,也證明volatile 這個關鍵字不具備原子性,

那volatile不適合如上計數場景,那volatile適合什麼樣的場景呢?

使用volatile必須具備兩個特點:

1、對變量的寫操作不依賴於當前值;

2、該變量沒有包含在具有其他變量的不變的式子中。

常見使用方案:將volatile修飾的變量作爲一個標誌性變量,和雙重檢查機制的方案中。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章