Java併發
併發的挑戰
上下文切換: 是消耗資源的操作,進入核心態需要
資源限制 : I/O 資料庫,cpu核數
死鎖 :等待不到需要的資源
volatile
記憶體語義
當寫一個volatile變數時,JMM會把該執行緒對應的本地記憶體中的共享變數值重新整理到主記憶體中。
當讀一個volatile變數時,JMM會把該執行緒對應的本地記憶體置為無效,執行緒接下來將從主記憶體中讀取共享變數
硬體實現
使用硬體指令當前快取行刷入主記憶體
是其他快取中此變數的快取行無效
使得讀操作需要重新從主記憶體載入此變數
適用場景
只有一個執行緒對volatile變數寫
Synchronized
鎖的物件
Java中的每一個物件都可以作為鎖。
對於同步方法,鎖是當前例項物件。
對於靜態同步方法,鎖是當前物件的Class物件。
對於同步方法塊,鎖是Synchonized括號裡配置的物件
實現
同步方法
使用 ACC_SYNCHRONIZED 標記符隱示的實現,原理是通過方法呼叫指令檢查該方法在常量池中是否包含 ACC_SYNCHRONIZED 標記符,JVM 要求執行緒在呼叫之前請求鎖
同步程式碼塊

JVM通過monitorenter和monitorexist指令實現同步鎖的獲取和釋放功能
monitorenter指令是在編譯後插入到同步程式碼塊的開始位置
monitorexit指令是插入到方法結束處和異常處
JVM要保證每個monitorenter必須有對應的monitorexit與之配對
任何物件都有一個monitor與之關聯,當且一個monitor被持有後,它將處於鎖定狀態
執行緒執行monitorenter指令時,將會嘗試獲取物件所對應的monitor的所有權,即嘗試獲得物件的鎖
執行緒執行monitorexit指令時,將會將進入次數-1直到變成0時釋放監視器
同一時刻只有一個執行緒能夠成功,其它失敗的執行緒會被阻塞,並放入到同步佇列中,進入BLOCKED狀態
虛擬機器做的鎖優化
1.鎖消除,消除無謂的鎖
2.鎖粗化,合併太小粒度的加鎖
3.鎖自旋,自適應自旋
4.鎖膨脹
Java物件頭

偏向鎖
為了在無多執行緒競爭的情況下儘量減少不必要的輕量級鎖執行路徑
,而偏向鎖則是在只有一個執行緒執行同步塊時進一步提高效能

輕量級鎖
目的是沒有多執行緒競爭的前提下,減少傳統的重量級鎖
輕量級鎖是為了線上程交替執行同步塊時提高效能

重量級鎖實現
Monitor Record結構
MonitorRecord(統一簡稱MR)是Java執行緒私有的資料結構,每一個執行緒都有一個可用MR列表,同時還有一個全域性的可用列表
一個被鎖住的物件都會和一個MR關聯(物件頭的MarkWord中的LockWord指向MR的起始地址)
MR中有一個Owner欄位存放擁有該鎖的執行緒的唯一標識,表示該鎖被這個執行緒佔用

Monitor Record工作機理

執行緒如果獲得監視鎖成功,將成為該監視鎖物件的擁有者
在任一時刻,監視器物件只屬於一個活動執行緒(Owner)
擁有者可以呼叫wait方法自動釋放監視鎖,進入等待狀態