-
一:java多線程互斥,和java多線程引入偏向鎖和輕量級鎖的緣由?
--->synchronized的重量級別的鎖,就是在線程運行到該代碼塊的時候,讓程序的運行級別從用戶態切換到內核態,把全部的線程掛起,讓cpu經過操做系統指令,去調度多線程之間,誰執行代碼塊,誰進入阻塞狀態。這樣會頻繁出現程序運行狀態的切換,線程的掛起和喚醒,這樣就會大量消耗資源,程序運行的效率低下。爲了提升效率,jvm的開發人員,引入了偏向鎖,和輕量級鎖,儘可能讓多線程訪問公共資源的時候,不進行程序運行狀態的切換,由用戶態進入內核態,藉助操做系統進行互斥。
--->jvm規範中能夠看到synchronized在jvm裏實現原理,jvm基於進入和退出Monitor對象來實現方法同步和代碼塊同的。在代碼同步的開始位置織入monitorenter,在結束同步的位置(正常結束和異常結束處)織入monitorexit指令實現。線程執行到monitorenter處,講會獲取鎖對象鎖對應的monitor的全部權,即嘗試得到對象的鎖。(任意對象都又一個monitor與之關聯,當且一個monitor被持有後,他處於鎖定狀態)
--->java的多線程安全是基於lock機制實現的,而lock的性能每每不如人意。緣由是,monitorenter與monitorexit這兩個控制多線程同步的bytecode原語,是jvm依賴操做系統互斥(mutex)來實現的。
--->互斥是一種會致使線程掛起,並在較短期內又須要從新調度回原線程的,較爲消耗資源的操做。
--->爲了優化java的Lock機制,從java6開始引入輕量級鎖的概念。輕量級鎖本意是爲了減小多線程進入互斥的概率,並非要替代互斥。它利用了cpu原語Compare-And-Swap(cas,彙編指令CMPXCHG),嘗試進入互斥前,進行補救。
鎖 |
優勢 |
缺點 |
適用場景 |
偏向鎖 |
加鎖和解鎖不須要額外的消耗,和執行非同步方法相比僅存在納秒級的差距 |
若是線程間存在鎖競爭,會帶來額外的鎖撤銷的消耗 |
適用於只有一個線程訪問同步塊場景 |
輕量級鎖 |
競爭的線程不會阻塞,提升了程序的響應速度 |
若是始終得不到索競爭的線程,使用自旋會消耗CPU |
追求響應速度,同步塊執行速度很是快 |
重量級鎖 |
線程競爭不使用自旋,不會消耗CPU |
線程阻塞,響應時間緩慢 |
追求吞吐量,同步塊執行速度較長 |
對象頭的存儲內容(monitor)java
長度 |
內容 |
說明 |
32/64bit |
Mark Word |
存儲對象的hashcode或鎖信息 |
32/64bit |
類對象的地址 |
存儲到對象類型數據的指針 |
32/64bit |
Array length |
數組的長度(若是當前對象是數組) |
Mark Word存儲內容(monitor)的狀態變化
鎖狀態 |
25bit,4bit |
1bit(是不是偏向鎖) |
2bit(鎖標示位) |
輕量級鎖 |
指向棧中鎖記錄的指針 |
|
00 |
重量級鎖 |
指向互斥量(重量級鎖)的指針 |
|
10 |
GC |
空 |
|
11 |
偏向鎖 |
線程id,對象hashcode,對象分代年齡 |
1 |
01 |
--->鎖一共有四種狀態(由低到高的次序):無鎖狀態,偏向鎖狀態,輕量級鎖狀態,重量級鎖狀態
--->鎖的等級只能夠升級,不能夠降級。這種鎖升級卻不能降級的策略,目的是爲了提升得到鎖和釋放鎖的效率。
--->a線程得到鎖,會在a線程的的棧幀裏建立lock record(鎖記錄變量),則在鎖對象的對象頭裏和lock record裏存儲a線程的線程id.之後該線程的進入,就不須要cas操做,只須要判斷是不是當前線程。
--->a線程獲取鎖,不會釋放鎖。直到b線程也要競爭該鎖時,a線程纔會釋放鎖。
--->偏向鎖的釋放,須要等待全局安全點(在這個時間點上沒有正在執行的字節碼),它會首先暫停擁有偏向鎖的線程,而後檢查持有偏向鎖的線程是否還活着,若是線程不處於活動狀態,則將對象頭設置成無鎖狀態。若是線程仍然活着,擁有偏向鎖的棧會被執行,遍歷偏向對象的所記錄。棧幀中的鎖記錄和對象頭的Mark Word要麼從新偏向其餘線程,要麼恢復到無鎖,或者標記對象不適合做爲偏向鎖。最後喚醒暫停的線程。
--->關閉偏向鎖,經過jvm的參數-XX:UseBiasedLocking=false,則默認會進入輕量級鎖。
--->a線程得到鎖,會在a線程的棧幀裏建立lock record(鎖記錄變量),讓lock record的指針指向鎖對象的對象頭中的mark word.再讓mark word 指向lock record.這就是獲取了鎖。
--->輕量級鎖,b線程在鎖競爭時,發現鎖已經被a線程佔用,則b線程不進入內核態,讓b線程自旋,執行空循環,等待a線程釋放鎖。若是,完成自旋策略仍是發現a線程沒有釋放鎖,或者讓c線程佔用了。則b線程試圖將輕量級鎖升級爲重量級鎖。
--->重量級鎖,就是讓爭搶鎖的線程從用戶態轉換成內核態。讓cpu藉助操做系統進行線程協調。