《java併發程式設計的藝術》併發底層實現原理
volatile
作用:當一個執行緒修改一個共享變數時,另一個執行緒能讀到這個修改的值。
定義:java程式語言允許執行緒訪問共享變數,為了確保共享變數能被準確和一致的更新,執行緒應該確保通過排他鎖單獨的獲得這個變數。
有volatile修飾的共享變數在進行寫操作時會多出第二行彙編程式碼
lock ...
該字首指令在多核處理器下會引發兩件事情:
1. 將當前處理器快取行的資料寫到系統記憶體。
2. 這個寫回記憶體的操作會使其他CPU裡快取了該記憶體地址的資料無效。
synchronizd
java中每一個物件都可以作為鎖,表現為以下3種形式
1. 對於普通同步方法,鎖是當前例項物件
2. 對於靜態同步方法,鎖是當前類的Class物件
3. 對於同步方法塊,鎖是synchronized
括號裡配置的物件。
JVM規範:JVM基於進入和退出Monitor
物件來實現方法同步和程式碼塊同步。
程式碼塊使用:monitorenter
和monitorexit
指令實現同步。
方法塊同樣可以使用上述方法。
monitorenter
指令是在編譯後插入到同步程式碼塊的開始位置。
monitorexit
插入到方法結束處和異常處。
每一個物件有一個monitor
相關聯,當一個monitor
被持有後處於鎖定狀態,執行緒執行到monitorenter
指令時,會嘗試獲取物件的鎖。另外monitorenter
和monitorexit
相對應。
java物件頭
長度 | 內容 | 說明 |
---|---|---|
32/64位 | Mark Word | 儲存物件的hashcode或鎖資訊等 |
32/64位 | Class Metadata Address | 儲存到物件型別資料的指標 |
32/64位 | Array length | 陣列的長度(如果當前物件是陣列) |
32位Mark word:
鎖狀態 | 25位 | 4位 | 1位(是否是偏向鎖) | 2位(鎖標誌位) |
---|---|---|---|---|
無鎖狀態 | 物件的hashcode | 物件分代年齡 | 0 | 01 |
64位Mark word:
鎖狀態 | 25位 | 31位 | 1位(cms_free) | 4位(分代年齡) | 1位(是否是偏向鎖) | 2位(鎖標誌位) |
---|---|---|---|---|---|---|
無鎖 | unused | hashcode | 0 | 01 | ||
偏向鎖 | threadID(54位)epoch(2位) | 1 | 01 |
鎖的升級和對比
遞增分為4種狀態:無鎖、偏向鎖、輕量級鎖、重量級鎖
只能升級,不能降級(提高獲得鎖和釋放鎖的效率)
偏向鎖
CAS(比較與交換,Compare and swap) 是一種有名的無鎖演算法。
1.當一個執行緒訪問同步塊並獲取鎖時,會在物件頭和棧幀的鎖記錄裡儲存鎖偏向的執行緒ID。
2.在下次執行緒進入或者退出同步塊時,測試物件頭的Mark Word
裡是否儲存著指向當前執行緒的偏向鎖。
3.如果測試成功,表示執行緒已經獲得了鎖,失敗則需要再測試Mark Word
中偏向鎖的標識是否設定為1(表示當前是偏向鎖)如果沒有設定則使用CAS
競爭鎖,否則嘗試使用CAS將物件頭的偏向鎖指向當前執行緒。
偏向鎖的撤銷:
偏向鎖使用了一種等到競爭出現才釋放鎖的機制。
1.首先暫停擁有偏向鎖的執行緒
2.然後檢查持有偏向鎖的執行緒是否存活,如果不處於活動狀態,將物件頭設定為無鎖狀態,如果執行緒存活,擁有偏向鎖的棧會被執行,遍歷偏向物件的鎖記錄棧中的鎖記錄和物件頭的Mark Word
要麼重新偏向於其他執行緒,要麼恢復到無鎖或者標記物件不適合作為偏向鎖,最後喚醒暫停的執行緒。
輕量級鎖
加鎖:
執行緒在執行同步塊之前,JVM會先在當前執行緒的棧幀中建立用於儲存鎖記錄的空間,並將物件頭中的Mark Word複製到鎖記錄中(Displaced Mark Word)然後執行緒嘗試使用CAS將物件頭的Mark Word替換為指向鎖記錄的指標。如果成功,當前執行緒獲得鎖,如果失敗,表示其他執行緒競爭鎖,當前執行緒嘗試使用自旋來獲取鎖。
解鎖:
使用原子的CAS操作將Displaced Mark Word替換回物件頭,通過成功表示沒有競爭發生,如果失敗,表示當前鎖存在競爭,鎖就會膨脹成重量級鎖。
原子操作
處理器提供匯流排鎖定和快取鎖定兩個機制來保證複雜記憶體操作的原子性。
1.使用匯流排鎖保證原子性
使用處理器提供的LOCK#訊號,當一個處理器在匯流排上輸出此訊號時,其他處理器的請求被阻塞,那麼該處理器可以獨佔共享記憶體。
2.使用快取鎖定保證原子性
快取鎖定:記憶體區域如果被快取在了處理器的快取行中,並且在Lock操作期間被鎖定,那麼當他執行鎖操作回寫到記憶體時,處理器修改內部的記憶體地址,用快取一致性(組織同時修改由兩個以上處理器快取的記憶體區域資料)保證一致性。
java實現原子操作
通過 鎖和迴圈CAS 的方式實現原子操作。
相關文章
- 【併發程式設計】(二)Java併發機制底層實現原理——synchronized關鍵字程式設計Javasynchronized
- 《java併發程式設計的藝術》併發工具類Java程式設計
- Java併發程式設計藝術Java程式設計
- 《java併發程式設計的藝術》併發容器和框架Java程式設計框架
- Java併發程式設計的藝術,解讀併發程式設計的優缺點Java程式設計
- 《java併發程式設計的藝術》Executor框架Java程式設計框架
- 《java併發程式設計的藝術》原子操作類Java程式設計
- Java併發程式設計的藝術(五)——中斷Java程式設計
- Java併發程式設計序列之JUC底層AQSJava程式設計AQS
- 併發程式設計基礎底層原理學習(二)程式設計
- 併發程式設計基礎底層原理學習(四)程式設計
- 併發程式設計基礎底層原理學習(一)程式設計
- 《java併發程式設計的藝術》記憶體模型Java程式設計記憶體模型
- 《java併發程式設計的藝術》執行緒池Java程式設計執行緒
- 【讀書筆記】Java併發程式設計的藝術筆記Java程式設計
- 併發機制的底層實現
- 【Java併發程式設計】Synchronized關鍵字實現原理Java程式設計synchronized
- Java併發容器,底層原理深入分析Java
- # iOS 一窺併發程式設計底層(一)iOS程式設計
- Java併發程式設計 - 第十一章 Java併發程式設計實踐Java程式設計
- java併發系列——底層CPUJava
- 如何評價《Java 併發程式設計藝術》這本書?Java程式設計
- Java併發程式設計:ThreadLocal的使用以及實現原理解析Java程式設計thread
- Java併發程式設計實踐Java程式設計
- Java 併發機制底層實現 —— volatile 原理、synchronize 鎖優化機制Java優化
- java併發程式設計系列:java併發程式設計背景知識Java程式設計
- java 併發程式設計Java程式設計
- Java併發程式設計Java程式設計
- 併發程式設計 join原理程式設計
- Java併發程式設計-鎖及併發容器Java程式設計
- Java併發程式設計---java規範與模式下的併發程式設計1.1Java程式設計模式
- java併發之SynchronousQueue實現原理Java
- 併發程式設計之 CAS 的原理程式設計
- Golang 併發程式設計(channel實現)Golang程式設計
- Java併發程式設計—ThreadLocalJava程式設計thread
- Java併發程式設計:synchronizedJava程式設計synchronized
- Java併發程式設計 -- ThreadLocalJava程式設計thread
- Java併發程式設計 -- ConditionJava程式設計