標籤:mic serial ++ 副本 其他 get 多個 關鍵字 int
可見度的概念
一個線程對共用變數值的修改,能夠及時地被其他線程看到
共用變數值:如果一個變數在多個線程的工作記憶體中都使用,存在副本,那麼這個變數就是這幾個線程的共用變數
兩條重要規定:
- 線程對共用變數的所有操作都必須在自己的工作記憶體中進行,不能直接從主記憶體中讀寫
- 不同線程之間無法直接存取其他線程工作記憶體中的變數,線程間變數值得傳遞需要通過主記憶體來完成
JMM(Java Memory Model)
- 所有的變數都儲存在主記憶體中
- 每個線程都有自己獨立的工作記憶體,裡面儲存該線程使用到的變數的副本(主記憶體中該變數的一份拷貝)
共用變數可見度實現原理
線程1把工作記憶體1中更新過的共用變數重新整理到主記憶體中,主記憶體把最新的共用變數的值更新到工作記憶體2中,線程2就能及時看到線程1的修改
synchronize實現可見度
- JMM關於synchronize的兩條規定
線程解鎖前,必須把共用變數的最新值重新整理到主記憶體中
線程加鎖是,將清空工作記憶體中共用變數的值,從而使用共用記憶體時,需要從主記憶體中重新讀取最新的值(加鎖和解鎖需要同一把鎖)
- 重排序 as-if-serial
volatile實現可見度
- volatile關鍵字:
能夠保證volatile變數的可見度
不能保證volatile變數複合操作的原子性
- volatile如何?記憶體可見度
通過加入記憶體屏障和禁止重排序最佳化來實現
對變數執行寫操作時,會在寫操作後加入一條store屏障指令
volatile 變數執行度操作時,會在讀操作前加入一條load屏障指令
- volatile不能保證原子性
當a線程的工作變數已經讀過變數的值後,即使b線程改變變數的值,並store到記憶體中,也不會觸發a線程load,因為a線程讀取時已經load過了。
- 保證變數自增操作的原子性
使用synchronize關鍵字
使用ReentrantLock(java.until.concurrent.locks)
使用AtomicInterger
(vava.util.concurrent.atomic)
- volatile適用場合
同時滿足:
- 對變數的寫入操作不依賴其當前值,
不滿足:number++,count=count*5等
滿足:boolean變數,記錄溫度變化的變數等
- 該變數沒有包含在具有其他變數的不變式中
不滿足:不變式low<up
final也可以保證記憶體可見度synchronize 和 volatile 比較
volatile不需要加鎖,不會阻塞線程
從記憶體可見度角度講volatile讀相當於加鎖,volatile寫相當於解鎖
synchronize既可以保證可見度和原子性
coding個人部落格連結
參考資料-視頻
多線程之記憶體可見度