一個想休息的線程:JVM究竟是怎麼處理鎖的?怎麼不讓我阻塞呢?

我是一個線程,生活在JVM(Java虛擬機)中, 這一段日子過得有些無聊,整個世界彷佛只有這一我的,每天忙着執行代碼,想休息一下都很難。程序員

 

我據說人類寫的代碼中有些特殊的地方,叫作臨界區,好比synchronized修飾的方法或者代碼塊,他們很是神奇,在同一時刻JVM老大隻容許一個線程進入執行。編程

 

實際上,老大設置了一把鎖,搶到了這把鎖就能夠執行,不然只能阻塞,等待別人釋放鎖。數據結構

 

老大說,阻塞就是不用幹活了,老老實實地等着就行。多線程

 

居然還有這等美事! 趕忙讓我阻塞一次吧。併發

 

但是老大又說:「每次設置鎖我都得和操做系統打交道,請他在內核中維護一個什麼Mutex(互斥量)的東西,他還得把大家這些線程阻塞,切換,這但是一筆巨大的費用啊,因此這些鎖仍是少用爲妙。」函數

 

我運氣也很差,我不知道執行了多少代碼,調用了多少函數,居然一次也沒遇到臨界區!操作系統

 

我想也許這個程序員編程時不當心,沒有考慮多線程併發的狀況; 也有多是這些程序大部分都是無狀態的,多少個線程執行都沒有問題。線程

 

因而我只好一直執行下去, 不知道過了多少天,我激動地發現,一個synchronized修飾的代碼塊終於出現了:3d

 

Account account = ...對象

synchronized(account){

    ...臨界區的代碼...

}

 

偏向鎖

 

我滿心指望別的線程已經進入了代碼塊,那我就能夠阻塞、休息。

 

即便沒有其餘線程進入臨界區,老大爲我申請鎖, 也得和操做系統協商什麼互斥量,從用戶態進入核心態,再從核心態返回用戶態,總要花些功夫吧。

 

但是老大根本沒有去找操做系統, 只是看了看這個account對象的所謂「對象頭」,其中有個叫作Mark Word的東西,彷佛是個什麼數據結構, 裏邊有幾個標識位,還有其餘數據。

 

 

老大隨手使用CAS操做把個人線程ID記錄到了這個Mark Word當中,修改了標識位,而後告訴我說: 能夠了,你如今擁有這把鎖了,進去執行代碼吧。

 

 

我驚奇地說:「老大你不和操做系統協商設置Mutex了?」

 

老大說:「不用了,你看如今就你一個線程進入了這個代碼塊,我只要記錄下你的線程ID,就表示你擁有這把鎖了,不用操做系統介入。」

 

我得到了鎖,開始執行被synchronized包裹的代碼塊。

 

等到我第二次執行到這個synchronized的時候,老大隻是看了一眼鎖對象account的Mark Word就說:「你的線程ID還在,還持有着這個對象的鎖,進入臨界區執行吧。」

 

我連喘口氣的機會都沒有,只好繼續執行。

 

老大說,這叫偏向鎖,在沒有別的線程競爭的時候,一直偏向我,可讓我一直執行下去。

 

我是多麼期盼來一個新的線程來和我競爭啊!

 

輕量級鎖

 

很快,機會就來了。

 

另一個線程0x3704也要進入這個代碼塊執行,可是鎖對象account 保存的是個人線程ID,他是無法進入臨界區的。

 

我心想,咱們兩個至少得有一個進入阻塞狀態,休息一下子了。

 

可是老大仍是不去操做系統協商,只是說: 我把這個偏向鎖升級一下,變成一個輕量級的鎖吧。

 

老大把鎖對象account恢復成無鎖狀態,在咱們倆的棧幀中各自分配了一個空間,叫作Lock Record, 把鎖對象account的Mark Word在咱們倆這裏各自複製了一份,叫作Displaced Mark Word, 這名字真奇怪。

 

而後把個人Lock Record的地址使用CAS放到了Mark Word當中,而且把鎖標誌位改成00, 這其實就意味着我也已經得到了這個輕量級的鎖了,能夠繼續進入臨界區執行。

 

 

0x3704沒有得到鎖,但仍是不阻塞,老大讓他自旋幾回,等待一下子。

 

等到我退出臨界區,釋放鎖的時候,須要把這個Displaced markd word 使用CAS複製回去。接下來他就能夠加鎖了。

 

咱們兩個交替着進入臨界區,執行這段代碼,相安無事,不多出現真正的競爭。

 

即便是出現了競爭,想得到鎖的線程只要自旋幾回,等待一下子,鎖就可能釋放了。

 

很明顯,若是沒有競爭或者輕度的競爭,輕量級鎖僅僅使用CAS操做和Lock record就避免了重量級互斥鎖的開銷,對JVM老大來講,確實是個好主意。

 

重量級鎖

 

輕量級鎖運行得挺好,我仍是沒有機會休息,終於有這麼一天,0x3704 正在持有鎖,在臨界區辛苦地執行代碼。 我自旋了好屢次,0x3704仍是沒釋放鎖。 這時候JVM老大說: 自旋次數太多了,太浪費CPU了,接下來升級爲重量級鎖!

 

這個重量級鎖須要操做系統的幫忙,依賴操做系統底層的Mutex Lock。

 

只見老大建立了一個monitor 對象, 把這個對象的地址更新到了Mark word當中。

 

鎖升級了!

 

 

因爲0x3704還在持有鎖運行,而我終於進入了求之不得的狀態:阻塞!  終於能夠休息一下了!

 

仔細一想,老大煞費心機地設置了偏向鎖和輕量級鎖,就是爲了不阻塞,避免操做系統的介入, 這兩種鎖無非就是針對這兩種狀況:

 

偏向鎖: 一般只有一個線程在臨界區執行

 

輕量級鎖: 能夠有多個線程交替進入臨界區,在競爭不激烈的時候,稍微自旋等待一下就能得到鎖。

 

至於重量級鎖,也是我最爲期待的鎖,那就是出現了激烈的競爭,只好讓咱們去阻塞休息了。

相關文章
相關標籤/搜索