欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的鎖與鎖的狀態(tài)升級詳細(xì)解讀

 更新時間:2024年01月29日 10:43:42   作者:Smallc0de  
這篇文章主要介紹了Java中的鎖與鎖的狀態(tài)升級詳細(xì)解讀,Java 1.6以后官方針對鎖的優(yōu)化,主要是增加了兩種新的鎖:偏向鎖和輕量級鎖,再加上本身重量級鎖,那么鎖基本上可以大致分為這三種,它們之間的區(qū)別主要是體現(xiàn)在等待時間上面,需要的朋友可以參考下

Java 1.6 的優(yōu)化

Java 1.6以后官方針對鎖的優(yōu)化,主要是增加了兩種新的鎖:偏向鎖和輕量級鎖。再加上本身重量級鎖,那么鎖基本上可以大致分為這三種,它們之間的區(qū)別主要是體現(xiàn)在等待時間上面。重量級鎖比較暴力,一旦某個資源被一個線程加了鎖,那么其他線程就不要再有任何想法了,必須等待其釋放資源才可以。如果時間較長,就會造成程序卡頓,甚至崩潰掉,為了改進(jìn)加了兩個新鎖。這兩種新鎖的概念是如何優(yōu)化的呢,就需要弄清楚對象和monitor的關(guān)系。

對象頭結(jié)構(gòu)

任何一個實(shí)例對象都有一些共同的信息即對象頭、實(shí)例變量、填充數(shù)據(jù)。其中對象頭就是加鎖的基礎(chǔ),其中存儲的就是加鎖的信息;實(shí)例變量就是存的屬性變量的信息,私有公有之類的;填充數(shù)據(jù)則是數(shù)據(jù)的起始地址。我們要說的還是對象頭,下面是對象頭結(jié)構(gòu):

長度內(nèi)容描述
32/64 bitMark Word存儲對象的hashCode或者鎖信息等
32/64 bitClass Metadata Address存儲到對象類型數(shù)據(jù)的指針
32/64 bitArray Length數(shù)組的長度,如果當(dāng)前對象是數(shù)組

從對象頭的信息來看,Mark Word就是存放鎖信息的地方,一共有32位用來存放鎖信息,信息格式如下:

在這里插入圖片描述

鎖的狀態(tài)

首先先解釋下上表中鎖狀態(tài)的含義:

無鎖狀態(tài):沒有加鎖,屬于樂觀鎖,鎖標(biāo)記01。

偏向鎖:在對象第一次被某一線程占有的時候,會檢查偏向鎖標(biāo)記,然后把偏向鎖標(biāo)記置1,表示線程被占用使用的是偏向鎖,鎖標(biāo)記置為01。接著寫入線程ID,表示當(dāng)前對象被哪個ID的線程占有了。當(dāng)此線程占有期間,其他的線程訪問的時候,就會有線程競爭。如果競爭成功,使用資源;如果競爭失敗則等待下次競爭,偏向鎖是輕量級鎖,屬于樂觀鎖。所謂的偏向鎖,會比較傾向于首次占有的線程,也就是說兩個線程競爭,第一次占有的線程會有比較大的概率分配到資源,這也就是偏向鎖名稱的由來:會偏向于首先占有該資源的線程。那么當(dāng)前線程一旦具有優(yōu)先權(quán),其他線程很可能長久無法獲取資源,為了改進(jìn)這樣一個狀態(tài),很多時候會采用大名鼎鼎非阻塞算法Compare and Swap(CAS)算法。正是因?yàn)檫@種特性,偏向鎖更加適合用于競爭不激烈的時候。由于偏向鎖會不斷地和無鎖狀態(tài)進(jìn)行切換,因此兩者使用時間也是接近的。

輕量級鎖:一般在線程有交替時使用。當(dāng)偏向鎖算法CAS競爭失敗,就會修改偏向鎖標(biāo)記為00,升級為輕量級鎖,屬于樂觀鎖。

重量級鎖:強(qiáng)互斥,鎖住資源后不允許其他線程競爭,其他線程要想訪問必須等待資源釋放,等待時間長。當(dāng)某資源已經(jīng)處于輕量級鎖的時候,會有別的線程前來競爭,繼續(xù)競爭失敗,則會修改標(biāo)記為10,變?yōu)橹亓考夋i,屬于悲觀鎖。

自旋鎖與鎖消除

鎖的升級也是要消耗時間的,尤其是不同等級之間的轉(zhuǎn)換消耗的時間更多。而輕量級鎖轉(zhuǎn)換成重量級鎖則是用戶線程和核心線程(操作系統(tǒng)本身的線程)之間的轉(zhuǎn)換非常耗時,所以我們要盡量減少這種轉(zhuǎn)換,所以有了這樣一種概念:當(dāng)競爭失敗的時候,先不著急進(jìn)行轉(zhuǎn)換,而是等待一會兒,由于線程執(zhí)行的非??欤赡苓€沒有升級到重量級鎖的時候,資源就已經(jīng)被釋放了。正是基于這樣一種邏輯,就有了自旋鎖這一概念。

自旋鎖:當(dāng)競爭失敗的時候,不是馬上轉(zhuǎn)化級別,而是執(zhí)行幾次空循環(huán),如果執(zhí)行空循環(huán)的時候,占有線程釋放了資源,那么就不需要進(jìn)行鎖的升級,直接進(jìn)行占用線程執(zhí)行就好了因此自旋鎖只是一種概念,并不是真正的鎖。

鎖消除: Java的即時編譯編譯器(JIT)在編譯的時候把不必要的鎖去掉。比如下面代碼,用來給變量a賦值,就完全沒有必要加鎖,因此這個synchronized在編譯的時候會被消去。

synchronized(this){
    int a=1;
}

鎖的升級

除了上面所說,還要明白一個概念,鎖永遠(yuǎn)都會加載對象(或者說堆中的資源上)上而不是線程上。所以升級過程為如下的步驟:

假設(shè):線程A訪問對象資源A則此時立刻對資源A加上偏向鎖保證線程A訪問資源A,且線程ID會被置為線程A。如果線程B來競爭,此時偏向鎖不會主動釋放,線程B可以看到該鎖并知曉資源A已經(jīng)被線程A使用,于是檢查此時資源A是否被線程A使用(即線程A是否還存活),那么:

  1. 如果線程A已經(jīng)銷毀,則資源A分配給線程B,即分配偏向鎖給線程B并把線程ID置為線程B。
  2. 如果線程A沒有銷毀,則檢查線程A的操作棧,檢查資源A的使用情況:
    • 如果線程A仍然在使用資源A,則把資源A升級為輕量級鎖,保證線程A的使用;
    • 如果資源A已經(jīng)不再使用,已經(jīng)被線程A釋放了,則資源A分配給線程B,后續(xù)同1。
  3. 資源A已經(jīng)由于競爭,升級為輕量級鎖(此時資源A依然是被線程A使用),線程B仍然需要競爭資源A。 因?yàn)檩p量級鎖會被認(rèn)為競爭程度低,所以線程B被允許嘗試競爭,當(dāng)線程B再次發(fā)現(xiàn)資源A被輕量級鎖鎖住時,線程B會進(jìn)入自旋狀態(tài)或者說自旋鎖(即空轉(zhuǎn)一定時間,比如空的循環(huán)等等,等待資源A被釋放)。此時認(rèn)為資源A會很快被釋放,所以線程B進(jìn)入空轉(zhuǎn)等待資源A。
  4. 但是當(dāng)自旋超過一定次數(shù),或者線程C在線程B自旋時,也來請求資源A,則資源A的輕量級鎖被升級為重量級鎖。由于重量級鎖能夠使得除了擁有當(dāng)前資源的線程以外的線程都阻塞,等待資源的釋放。所以此時資源A和線程A被重量級鎖綁在一起,不會釋放給線程B、線程C,因此線程B和線程C必須等待線程A釋放資源A以后在進(jìn)行新的競爭

說完這些,可能大家會有個疑問:為什么要進(jìn)行鎖的升級?假如很多線程都是處于輕量級上,都處于自旋狀態(tài),那么其中正在運(yùn)行一個線程以及釋放鎖了,但是此時有很多線程在自旋,都在相互競爭??赡茉斐伤械木€程都會一直自旋下去,CPU空轉(zhuǎn)。為了阻止CPU空轉(zhuǎn),所以用重量級鎖把除了正在運(yùn)行的線程以外的所有線程阻塞,保證不會有新的競爭。但是要注意的是鎖是由低到高的升級,而且只會升級,而不會降級。因?yàn)榧幢闶侵亓考夋i一旦占有線程釋放了,就直接是無鎖狀態(tài),不存在一層一層降級的過程。

鎖的重入性

當(dāng)有些時候必須對某個資源進(jìn)行二次加鎖也是可以的,比如下面這段代碼做了多重加鎖。

這樣也是可以的,之前的博客中說過Java中每一個對象都有一個monitor對象,也就是一個監(jiān)視器,加鎖就是通過這個監(jiān)視器去加鎖。

當(dāng)某一個線程要占有這個對象的時候,先去檢查monitor對象的計(jì)數(shù)器是不是0,如果是0表示沒有線程占有這個對象,則成功占有這個對象,并且對這個對象的monitor計(jì)數(shù)器+1。

如果不為0,則說明這個對象已經(jīng)被別的線程占用,那么就等待。當(dāng)線程釋放某個對象的占有時monitor的計(jì)數(shù)器-1。

注意這里是減一不是置0,也就是說同一線程可以對同一對象進(jìn)行多次加鎖,進(jìn)行不斷地+1、+1,這個就是線程的重入性。

public synchronized void methodName3(){
    synchronized (this){
        // code ......
        synchronized (this){		//加鎖的對象不同也可以,但是要避免對象交叉造成的死鎖
            // code ......
            synchronized (this){
                // code ......
            }
        }
    }
}

悲觀鎖與樂觀鎖

悲觀鎖:一般指寫操作比較多,包括增刪改,讀操作(查)比較少的鎖。也指不允許競爭的鎖,遇到必須等待。

樂觀鎖:一般指讀(查)操作比較多,但是寫操作比較少的鎖。也指可以競爭的鎖,可以嘗試競爭。 因此很多時候悲觀鎖一般要加鎖,樂觀鎖一般只用版本控制,讀取到最新的數(shù)據(jù)即可。只是一個概念,并不特地指某種所。

公平鎖與非公平鎖

公平鎖:其實(shí)就是排隊(duì),先來先得FIFO的邏輯,因此每個鎖都是公平的。

非公平鎖:就是采用一定的算法或者優(yōu)先度去對線程拿到鎖的順序進(jìn)行調(diào)整,因此每個鎖并不是公平獲取資源的。 這兩個鎖各有優(yōu)缺點(diǎn),使用誰要看具體需求,比如緊急剎車作為一個功能來說,就必須用非公平鎖。

死鎖

當(dāng)由加鎖導(dǎo)致A線程等B線程釋放資源,B線程等A線程釋放資源,結(jié)果線程A和線程B都無法獲取資源導(dǎo)致,程序卡死在這里的情況就是死鎖。

總結(jié)

本篇延續(xù)著synchronized關(guān)鍵字的部分內(nèi)容,對鎖的概念、鎖的原理以及鎖的升級,進(jìn)行了一個剖析,希望能夠?qū)Ω魑焕斫釰ava中的鎖有所幫助。

到此這篇關(guān)于Java中的鎖與鎖的狀態(tài)升級詳細(xì)解讀的文章就介紹到這了,更多相關(guān)Java鎖與鎖的狀態(tài)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java web實(shí)現(xiàn)簡單聊天室

    java web實(shí)現(xiàn)簡單聊天室

    這篇文章主要為大家詳細(xì)介紹了java-web實(shí)現(xiàn)簡單聊天室,含拍一拍功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Java 通過反射變更String的值過程詳解

    Java 通過反射變更String的值過程詳解

    這篇文章主要介紹了Java 通過反射變更String的值過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • SSh結(jié)合Easyui實(shí)現(xiàn)Datagrid的分頁顯示

    SSh結(jié)合Easyui實(shí)現(xiàn)Datagrid的分頁顯示

    這篇文章主要為大家詳細(xì)介紹了SSh結(jié)合Easyui實(shí)現(xiàn)Datagrid的分頁顯示的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Spring?Data?Redis切換底層Jedis和Lettuce實(shí)現(xiàn)源碼解析

    Spring?Data?Redis切換底層Jedis和Lettuce實(shí)現(xiàn)源碼解析

    這篇文章主要為大家介紹了Spring?Data?Redis切換底層Jedis和Lettuce實(shí)現(xiàn)方法源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 分享Java多線程實(shí)現(xiàn)的四種方式

    分享Java多線程實(shí)現(xiàn)的四種方式

    這篇文章主要介紹了分享Java多線程實(shí)現(xiàn)的四種方式,文章基于?Java的相關(guān)資料展開多線程的詳細(xì)介紹,具有一的的參考價值,需要的小伙伴可以參考一下
    2022-05-05
  • Spring Security跳轉(zhuǎn)頁面失敗問題解決

    Spring Security跳轉(zhuǎn)頁面失敗問題解決

    這篇文章主要介紹了Spring Security跳轉(zhuǎn)頁面失敗問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • Spring?Boot統(tǒng)一處理全局異常的實(shí)戰(zhàn)教程

    Spring?Boot統(tǒng)一處理全局異常的實(shí)戰(zhàn)教程

    最近在做項(xiàng)目時需要對異常進(jìn)行全局統(tǒng)一處理,所以下面這篇文章主要給大家介紹了關(guān)于Spring?Boot統(tǒng)一處理全局異常的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • springboot攔截器不攔截靜態(tài)資源,只攔截controller的實(shí)現(xiàn)方法

    springboot攔截器不攔截靜態(tài)資源,只攔截controller的實(shí)現(xiàn)方法

    這篇文章主要介紹了springboot攔截器不攔截靜態(tài)資源,只攔截controller的實(shí)現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • elasticsearch索引index之put?mapping的設(shè)置分析

    elasticsearch索引index之put?mapping的設(shè)置分析

    這篇文章主要為大家介紹了elasticsearch索引index之put?mapping的設(shè)置分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • JVM類加載之雙親委派機(jī)制解讀

    JVM類加載之雙親委派機(jī)制解讀

    這篇文章主要介紹了JVM類加載之雙親委派機(jī)制解讀,類加載階段分為加載、連接、初始化三個階段,而加載階段需要通過類的全限定名來獲取定義了此類的二進(jìn)制字節(jié)流,Java特意把這一步抽出來用類加載器來實(shí)現(xiàn),需要的朋友可以參考下
    2023-12-12

最新評論