日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java互斥锁的实现原理_java-深入分析synchronized原理

發(fā)布時(shí)間:2024/7/23 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java互斥锁的实现原理_java-深入分析synchronized原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

互斥鎖

互斥鎖futex,全拼fast userspace mutexes,直翻為快速用戶空間互斥器,它是我們上層應(yīng)用實(shí)現(xiàn)鎖的最常用方法。futex是一塊所有進(jìn)程都可以訪問(wèn)的內(nèi)存,是通過(guò)cpu的原子操作修改內(nèi)存中的值來(lái)嘗試獲取瑣,如果沒(méi)有競(jìng)爭(zhēng),則直接在用戶空間完成操作,無(wú)需切換內(nèi)核空間,以此保證了futex的性能。

synchronized

其實(shí)java多線程操作大體就那么幾種,基于cas的aqs,synchronized和volatile,這篇文章主要介紹下synchronized。

synchronized是java的關(guān)鍵字,在老版本的jdk中性能表現(xiàn)并不太好,所以有了很多基于cas的Lock,但最近幾版jdk都對(duì)synchronized做了很多優(yōu)化,以后synchronized也會(huì)作為jdk主推的鎖。

synchronized最主要的優(yōu)化就是引入了升級(jí)功能,升級(jí)主要分偏向鎖、輕量級(jí)鎖、重量級(jí)鎖。

synchronized因?yàn)橛猩?jí)和降級(jí),既不會(huì)直接粗暴的使用互斥鎖,也不會(huì)有cas鎖在超高并發(fā)下多次嘗試引起的性能問(wèn)題,所以相比juc的cas鎖,synchronized在大多數(shù)情況下性能更好。

synchronized的使用方法主要有3種

//加鎖到靜態(tài)方法上

public static synchronized void test();

//加鎖到實(shí)例方法上

public synchronized void test();

//加鎖到對(duì)象上

synchronized(this){

}

// 加鎖在靜態(tài)方法上同加鎖到類對(duì)象上

synchronized(Test.class){

}

// 加鎖到實(shí)例方法上同加鎖到當(dāng)前對(duì)象上

synchronized(this){

}

總體上說(shuō),不管是鎖類對(duì)象,還是鎖其它對(duì)象都是鎖到一個(gè)對(duì)象上了。

這張圖很重要,在下面會(huì)多次用到,就先放這里了。

偏向鎖

java為了支持鎖對(duì)象,在對(duì)象頭上做了上圖的設(shè)計(jì),markword是對(duì)象頭中的一部分,64位虛擬機(jī)占64bit,markword在不同等級(jí)鎖狀態(tài)下存儲(chǔ)的內(nèi)容是不同的,上圖是鎖處于不同狀態(tài)時(shí)markword存儲(chǔ)的內(nèi)容。

其實(shí)經(jīng)過(guò)大量測(cè)試在我們使用synchronized時(shí),大多數(shù)情況并沒(méi)有發(fā)生競(jìng)爭(zhēng),很多訪問(wèn)都發(fā)生在一個(gè)線程里,所以設(shè)計(jì)了偏向鎖,偏向鎖的意思就是鎖偏向某個(gè)線程。

當(dāng)我們嘗試給一個(gè)對(duì)象加鎖時(shí),會(huì)有幾種情況。

未偏向:如果lock為01時(shí),biased_lock為0,表示沒(méi)有線程持有這個(gè)對(duì)象的偏向鎖,線程會(huì)通過(guò)cas的方式修改對(duì)象頭獲取偏向鎖。

可重偏向:如果lock為01時(shí),biased_lock為1,表示對(duì)象被偏向鎖定,這時(shí)還會(huì)拿epoch與klass(可以理解為某個(gè)Class在虛擬機(jī)中對(duì)應(yīng)的對(duì)象)的mark_prototype的epoch作比較,如果不一致表示可重偏向,線程會(huì)通過(guò)cas的方式修改對(duì)象頭獲取偏向鎖。

已偏向:lock為01,biased_lock為1,epoch與mark_prototype的epoch相等表示鎖已偏向,會(huì)比較thread字段的threadId,如果一致表示持有鎖的是當(dāng)前線程,可以重入。

如果沒(méi)有獲取到偏向鎖,就需要進(jìn)行一個(gè)撤銷偏向鎖并升級(jí)偏向鎖的過(guò)程,這個(gè)過(guò)程比較消耗性能,所以當(dāng)某類對(duì)象,比如我們的User.class這個(gè)對(duì)象的實(shí)例有很多次撤銷(默認(rèn)值為40),虛擬機(jī)就會(huì)更新klass的epoch,表示可重偏向,這就是為啥鎖的是對(duì)象,判斷epoch是去klass判斷。

輕量鎖

當(dāng)未獲取到偏向鎖時(shí),需要通知持有偏向鎖的線程撤銷偏向鎖,競(jìng)爭(zhēng)線程則進(jìn)行一個(gè)輕量級(jí)鎖加鎖的過(guò)程。

偏向鎖的撤銷:持有鎖的線程進(jìn)入safepoint時(shí),判斷持有鎖的線程是否在加鎖狀態(tài),如果是則直接修改markword為輕量級(jí)鎖,否則釋放偏向鎖,表示未鎖定、

輕量級(jí)鎖加鎖:虛擬機(jī)會(huì)在當(dāng)前線程的棧幀中創(chuàng)建一個(gè)lock record,并拷貝markword到lockrecord,再通過(guò)cas把對(duì)象的markword改為偏向鎖,ptr_to_lock_record指向lockrecord,如果cas成功則表示成功獲取輕量級(jí)鎖,否則進(jìn)行自旋嘗試,就是常說(shuō)的自旋鎖。

輕量級(jí)鎖釋放:輕量級(jí)鎖釋放時(shí),只要把lockrecord中的markword替換回對(duì)象頭的markword就釋放成功了。

重量級(jí)鎖

當(dāng)自旋嘗試次數(shù)超過(guò)閾值(jvm控制的動(dòng)態(tài)值),鎖就會(huì)進(jìn)一步升級(jí),升級(jí)為重量級(jí)鎖。

升級(jí)為重量鎖后,線程就會(huì)出現(xiàn)等待、阻塞、喚醒等各種操作,就會(huì)涉及到用戶態(tài)和內(nèi)核態(tài)的切換,所以叫重量級(jí)鎖,重量級(jí)鎖的實(shí)現(xiàn)就是文中最開(kāi)始提到的futex互斥鎖實(shí)現(xiàn)的。

重量級(jí)鎖既然需要線程的管理機(jī)制,自然引入了管程(monitor),java的管程模式類似mesa。

contentionList: 所有想要競(jìng)爭(zhēng)的線程都要進(jìn)入的隊(duì)列,又叫cxq。

entrylist: 準(zhǔn)備競(jìng)爭(zhēng)的線程都在這個(gè)隊(duì)列,這個(gè)隊(duì)列只有空的時(shí)候才去cxq中拉去,cxq每次只會(huì)有一個(gè)進(jìn)去entrylist。

OnDeck:entrylist中的一個(gè)線程,一般為最前面的線程,只有OnDeck線程才會(huì)去競(jìng)爭(zhēng)鎖、

waitset:當(dāng)我們調(diào)用wait()方法時(shí),線程就會(huì)進(jìn)入waitset,被notity后直接進(jìn)入entrylist,所以被喚醒的線程比剛參與競(jìng)爭(zhēng)的線程優(yōu)先級(jí)更高。

總結(jié)

以上是生活随笔為你收集整理的java互斥锁的实现原理_java-深入分析synchronized原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。