1. 程式人生 > >併發程式設計的藝術——第二章Java併發機制的底層實現原理

併發程式設計的藝術——第二章Java併發機制的底層實現原理

第一節 volatile的應用

定義:Java程式語言允許執行緒訪問共享變數,為了確保共享變數能被準確和一致地更新,執行緒應該確保通過排他鎖單獨獲得這個變數。

為了提高處理速度,處理器不直接和記憶體進行通訊,而是先將系統記憶體的資料讀到內部快取後再進行操作

在多處理器下, 為了保證各個處理器的快取是一致的,就會實現快取一致性協議,每個處理器通過嗅探在總線上的傳播資料來檢查自己快取的值是不是過期了,當處理器發現自己的快取行對應的記憶體地址唄修改,就會將當前處理器的快取設定為無效狀態,當處理器對這個資料進行修改操作時,會重新從系統記憶體中把資料督導處理器快取裡。

volatile兩條實現原則:

  1. Lock字首指令會引起處理器快取寫回到記憶體
  2. 一個處理器的快取寫回到記憶體會導致其他處理器快取無效

第二節synchronized的實現原理與應用

synchronized也稱為重量級鎖,鎖的三種形式:

  1. 對於普通同步方法,鎖是當前例項物件
  2. 對於靜態同步方法,鎖是當前類的Class物件
  3. 對於同步程式碼塊,鎖是synchronized括號裡面配置的物件

程式碼塊同步時使用monitorenter和monitorexit指令實現的,monitorenter指令是在編譯後插入到同步程式碼塊的開始位置,而monitorexit是插入到方法結束處和異常處,JVM要保證每個monitorenter必須有monitorexit與之對應。任何物件都有一個monitor與之關聯,當且僅當一個monitor被持有後,它將處於鎖定狀態。

一Java物件頭

synchronized使用的鎖是存在Java物件頭裡的。

Java物件頭裡的Mark Word裡預設儲存物件的HashCode,分代年齡和鎖標記位。

二鎖的升級與對比

JavaSE1.6將鎖分為4種狀態,級別從低到高:無鎖狀態,偏向鎖狀態,輕量級鎖狀態,重量級鎖狀態。鎖只能升級,不能降級。

偏向鎖:(為了讓執行緒獲得鎖的代價更低)當一個執行緒訪問你同步程式碼塊時,首先檢查物件頭中是否儲存了該執行緒的ID,如果沒有使用CAS替換Mark Word,測試物件頭中Mark Word中的執行緒ID是否執行自己,如果只想自己則執行同步體

輕量級鎖:線上程執行程式碼塊之前,JVM會分配空間並將物件頭中的Mark Word複製到棧幀中,然後執行緒嘗試使用CAS將物件頭中的Mark Word替換為執行鎖記錄的指標,如果成功,將Mark Word替換為輕量級鎖,並執行方法體;如果失敗,則當前執行緒嘗試使用自旋來獲得鎖,如果還是獲取失敗,鎖將膨脹為重量級鎖。在輕量級鎖解鎖時,會使用原子的CAS操作將棧中的資訊替換回到物件頭。

三原子操作的實現原理

處理器實現原子操作的方式:

  1. 通過匯流排鎖保證原子性
  2. 通過快取鎖定保證原子性

CAS實現原子操作的三大問題:

  1. ABA 問題(使用compareAndSet方法)
  2. 迴圈時間長,開銷大
  3. 只能保證一個共享變數的原子操作