Java偏向鎖\輕量級鎖\重量級鎖總結
|
資源消耗 |
目的 |
場景 |
實現方式 |
偏向鎖 |
一個執行緒只有一次CAS |
單執行緒進行同步塊時,消除輕量級鎖的CAS操作。 |
大多數場景為單執行緒訪問同步塊,一旦有競爭,偏向鎖失效。 |
判斷markword是否指現當前執行緒 |
輕量級鎖 |
每次進出同步塊,都要進行CAS設定Mark word,出現鎖競爭時,自旋獲得鎖,不進行使用者態與核心態切換。 |
以自旋與CAS操作的方式進行執行緒同步,減少執行緒態切換帶來的效能問題 |
追求相應時間; 同步塊執行很快時,一旦超過自旋閾值,則升級為重量級鎖 |
判斷markword是否指現當前執行緒的 lock record |
重量級鎖 |
每次進出同步塊,都要進行CAS設定Mark word,出現鎖競爭時,執行緒阻塞掛起,進行使用者態與核心態切換。 |
執行緒同步 |
追求吞吐量; 同步塊執行時間長 |
判斷markword是否指現鎖對像。 |
偏向鎖
Java偏向鎖旨在對於無併發爭用的前提下,進行真正意義上的無鎖同步。個人理解就是執行緒在獲取鎖之前先檢查是否偏向,偏向了就直接拿物件頭中儲存的執行緒ID與當前執行緒做比較,如果一致就繼續執行,不一致就撤銷偏向,走無偏向鎖定流程。
關於這裡面的撤銷偏向,是通知已經獲取偏向鎖的執行緒撤銷(也就是物件頭記錄的執行緒ID),還是爭用偏向鎖的執行緒(即當前執行緒)撤銷呢?撤銷的具體過程又是什麼樣的呢?
1、偏向鎖升級:一個物件剛開始例項化的時候,沒有任何執行緒來訪問它的時候。它是可偏向的,意味著,它現在認為只可能有一個執行緒來訪問它。
hash |
age |
是否偏向鎖:1 |
鎖標識位:01 |
2、所以當第一個執行緒來訪問它的時候,它會偏向這個執行緒,此時,物件持有偏向鎖。偏向第一個執行緒,這個執行緒在修改物件頭MarkWord成為偏向鎖的時候使用
執行緒ID |
epoch |
age |
是否偏向鎖:1 |
鎖標識位:01 |
3、一旦有第二個執行緒訪問這個物件,因為偏向鎖不會主動釋放,所以第二個執行緒可以看到物件時偏向狀態,這時表明在這個物件上已經存在競爭了,檢查原來持有該物件鎖的執行緒是否依然存活,如果掛了,則可以將物件變為無鎖狀態,然後重新偏向新的執行緒。
設定成無鎖狀態。????無鎖狀態是下面的哪種????
hash |
Age |
是否偏向鎖:1 |
鎖標識位:01 |
null |
epoch |
age |
是否偏向鎖:1 |
鎖標識位:01 |
重新偏向執行緒2
執行緒2ID |
age |
是否偏向鎖:1 |
鎖標識位:01 |
4、如果原來的執行緒依然存活,則馬上執行那個執行緒的操作棧,檢查該物件的使用情況,如果仍然需要持有偏向鎖,則偏向鎖升級為輕量級鎖(偏向鎖就是這個時候升級為輕量級鎖的)。
先標記為非偏向模式
Hash |
age |
是否偏向鎖:0 |
鎖標識位:01 |
再進行輕量級鎖升級
Lock record 地址 |
鎖標識位:00 |
此後物件再也回不到偏向鎖模式
5、如果不存在使用了,則可以將物件回覆成無鎖狀態,然後重新偏向。
設定成無鎖狀態。????無鎖狀態是下面的哪種????
hash |
Age |
是否偏向鎖:1 |
鎖標識位:01 |
null |
epoch |
age |
是否偏向鎖:1 |
鎖標識位:01 |