一、可見性:
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修飾的變量作爲一個標誌性變量,和雙重檢查機制的方案中。