12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
小陳:呼叫老王......
老王:來(lái)了來(lái)了,小陳你準(zhǔn)備好了嗎?今天我們來(lái)講synchronized的鎖重入、鎖優(yōu)化、和鎖升級(jí)的原理
小陳:早就準(zhǔn)備好了,我現(xiàn)在都等不及了
老王:那就好,那我們廢話不多說(shuō),直接開(kāi)始第一個(gè)話題:synchronized是怎么實(shí)現(xiàn)鎖重入的?
synchronized的鎖重入
小陳:老王,其實(shí)這個(gè)問(wèn)題,之前我看了前幾篇講的,就知道了。
老王:哦,看來(lái)你是有準(zhǔn)備的,那你來(lái)說(shuō)說(shuō)......
小陳:所謂鎖重入,就是支持正在持有鎖的線程支持再次獲取鎖,不會(huì)出現(xiàn)自己鎖死自己的問(wèn)題。
老王:嗯嗯,沒(méi)錯(cuò)的
小陳:我打個(gè)比方,比如以下的代碼:
synchronized(this) {synchronized(this){synchronized(this){synchronized(this){synchronized(this){ ........ } } } } }可能對(duì)應(yīng)下面的指令:
monitorenter monitorentermonitorentermonitorentermonitorenter......monitorexit monitorexit monitorexitmonitorexit monitorexit回顧之前講的加鎖就是將_count 由 0 設(shè)置為1,將_owner指向自己,這里的_owner就是指向加鎖的線程。
(1)所以再次重入加鎖的時(shí)候,發(fā)現(xiàn)有人加鎖了,同時(shí)檢查_owner是不是自己加鎖的,如果是自己加鎖的,只需要將_count 次數(shù)加1即可。
(2)同樣,在釋放鎖的時(shí)候執(zhí)行monitorexit指令,首先將_count進(jìn)行減1,當(dāng)_count 減少到0的時(shí)候表示自己釋放了鎖,然后將_owner 指向null。
小陳:所以,根據(jù)上訴鎖重入的方式,代碼進(jìn)入了5次synchronized 相當(dāng)于執(zhí)行了5次monitorenter加鎖,最后_count = 5。 當(dāng)5次monitorexit執(zhí)行完了之后,_count = 0即釋放了鎖。
老王:很好,說(shuō)得很詳細(xì),鼓掌鼓掌.......
鎖消除
老王:小陳啊,鎖重入這個(gè)你理解得很不錯(cuò),鎖消除這個(gè)你再來(lái)說(shuō)說(shuō)..
小陳:鎖消除啊,這個(gè)也很簡(jiǎn)單,就是在不存在鎖競(jìng)爭(zhēng)的地方使用了synchronized,jvm會(huì)自動(dòng)幫你優(yōu)化掉,比如說(shuō)下面的這段代碼......
public void business() {// lock對(duì)象方法內(nèi)部創(chuàng)建,線程私有的,根本不會(huì)引起競(jìng)爭(zhēng)Object lock = new Object();synchronized(lock) {i++;j++;// 其它業(yè)務(wù)操作 } }上面的這段代碼,由于lock對(duì)象是線程私有的,多個(gè)線程不會(huì)共享;像這種情況多線程之間沒(méi)有競(jìng)爭(zhēng),就沒(méi)必要使用鎖了,就有可能被JVM優(yōu)化成以下的代碼:
public void business() {i++;j++;// 其它業(yè)務(wù)操作 }小陳:這就是我理解的鎖消除,只有一個(gè)線程會(huì)用到,不會(huì)引起多個(gè)線程競(jìng)爭(zhēng)的;相當(dāng)于就自己用,沒(méi)必要加鎖了。
老王:嗯嗯,這個(gè)鎖消除也理解的不錯(cuò)......
synchronized鎖升級(jí)
老王:那synchronized的鎖升級(jí)原理呢? 你來(lái)說(shuō)說(shuō)
小陳:額,這個(gè)鎖升級(jí)其實(shí)我了解得不深,還比較模糊,還是老王您來(lái)講吧......
老王:哈哈,好。講解鎖升級(jí)之前,我先問(wèn)個(gè)問(wèn)題,synchronized為什么要設(shè)計(jì)成可升級(jí)的鎖呢?
小陳:這個(gè),我理解的就是希望能盡量花費(fèi)最小的代價(jià)能達(dá)到目的。
老王:嗯嗯,是這個(gè)理由沒(méi)錯(cuò);但是你知道synchronized在什么鎖的情況下花費(fèi)什么代價(jià)嗎?以及每次升級(jí)之后花費(fèi)了什么代價(jià)嗎?
小陳:額,這個(gè)......,不清楚
老王:在說(shuō)這個(gè)之前,我先給你看一下前兩章都講解過(guò)Mark Word的圖,我們?cè)賮?lái)回顧一下:
之前我們說(shuō)過(guò),Mark Word是一個(gè)32bit位的數(shù)據(jù)結(jié)構(gòu),最后兩位表示的是鎖標(biāo)志位,當(dāng)Mark Word的鎖標(biāo)志位不同的時(shí)候,代表Mark Word 中記錄的數(shù)據(jù)不一樣。
(1)比如鎖模式標(biāo)志位是,也就是最后兩位是01的時(shí)候,表示處于無(wú)鎖模式或者偏向鎖模式。
無(wú)鎖:如果此時(shí)偏向鎖標(biāo)志,倒數(shù)第3位,是0,即最后3位是001,表示當(dāng)前處于無(wú)鎖模式,此時(shí)Mark Word就常規(guī)記錄對(duì)象hashcode、GC年齡信息。
偏向鎖:倒數(shù)第3位是1,即Mark word最后3位是101,則表示當(dāng)前處于偏向鎖模式,那么Mark Word就記錄獲取了偏向鎖的線程ID、對(duì)象的GC年齡。
(2)輕量級(jí)鎖:當(dāng)鎖模式標(biāo)志位是00的時(shí)候,表示當(dāng)前處于輕量級(jí)鎖模式,此時(shí)會(huì)生成一個(gè)輕量級(jí)的鎖記錄,存放在獲取鎖的線程棧空間中,Mark Word此時(shí)就存儲(chǔ)這個(gè)鎖記錄的地址。
Mark Word存儲(chǔ)的地址在哪個(gè)線程的棧空間中,就表示哪個(gè)線程獲取到了輕量級(jí)鎖。
(3)重量級(jí)鎖:當(dāng)鎖模式標(biāo)志位是10的時(shí)候,表示當(dāng)前處于重量級(jí)鎖模式,此時(shí)加鎖就不是Mark Word的責(zé)任了,需要找monitor鎖監(jiān)視器,這個(gè)上一章我們已經(jīng)講解monitor加鎖的原理了。
此時(shí)Mark Word就記錄了一下monitor的地址,然后有線程找Mark Word的時(shí)候,Mark Word就把monitor地址給它,告訴線程自個(gè)根據(jù)這個(gè)地址找monitor進(jìn)行加鎖。
老王:小陳啊,這個(gè)是我們前兩章講解過(guò)的內(nèi)容,這些都還記得不?
小陳:嗯嗯,這些我都知道,老王你前面兩章已經(jīng)分析得非常細(xì)致了。
老王:那好,我就不繼續(xù)啰嗦了,首先馬上進(jìn)入synchronized鎖升級(jí)過(guò)程中,偏向鎖的講解。
偏向鎖
如果上表格所示,當(dāng)有線程第一次進(jìn)入synchronized的同步代碼塊之內(nèi),發(fā)現(xiàn):
Mark Word的最后三位是001,表示當(dāng)前無(wú)鎖狀態(tài),說(shuō)明鎖的這時(shí)候競(jìng)爭(zhēng)不激烈啊。
于是選擇代價(jià)最小的方式,加了個(gè)偏向鎖,只在第一次獲取偏向鎖的時(shí)候執(zhí)行CAS操作(將自己的線程Id通過(guò)CAS操作設(shè)置到Mark Word中),同時(shí)將偏向鎖標(biāo)志位改為1。
后面如果自己再獲取鎖的時(shí)候,每次檢查一下發(fā)現(xiàn)自己之前加了偏向鎖,就直接執(zhí)行代碼,就不需要再次加鎖了......
老王:說(shuō)到這里,你知道偏向鎖的原理了沒(méi)?
小陳:明白了,感情線程A這個(gè)家伙加鎖的時(shí)候發(fā)現(xiàn)之前沒(méi)人加過(guò)鎖,所以這家伙很自私,加了個(gè)偏向鎖指向了自己,后面自己再進(jìn)入synchronized的時(shí)候就不需要加鎖了,嘿嘿,原來(lái)是這樣啊
老王:沒(méi)錯(cuò),就是這樣......
老王:加了偏向鎖的人確實(shí)是個(gè)自私的人,這家伙用完了鎖之后,自己加鎖時(shí)候修改過(guò)的Mark Word信息都不會(huì)再改回來(lái)了,也就是它不會(huì)主動(dòng)釋放鎖。
小陳:啊這...,這個(gè)哥們不釋放鎖,如果它用完了,別人這個(gè)時(shí)候需要進(jìn)入synchronized代碼塊怎么辦?
老王:你說(shuō)的這個(gè)問(wèn)題啊,其實(shí)JVM的設(shè)計(jì)者也考慮到了,這就涉及到一個(gè)重偏向的問(wèn)題。
偏向鎖之重偏向
老王:我給你舉個(gè)例子說(shuō)明一下重偏向咋回事:
線程B去申請(qǐng)加鎖,發(fā)現(xiàn)是線程A加了偏向鎖;這時(shí)候回去判斷一下線程A是否存活,如果線程A掛了,就可以重新偏向了,重偏向也就是將自己的線程ID設(shè)置到Mark Word中。
如果線程A沒(méi)掛,但是synchronized代碼塊執(zhí)行完了,這個(gè)時(shí)候也可以重新偏向了,將偏向標(biāo)識(shí)指向自己,輪到我了,哈哈。
老王:小陳啊,這就回答了你的問(wèn)題了,線程A用完了這家伙不把Mark Word標(biāo)識(shí)改回來(lái);沒(méi)關(guān)系啊,線程B判斷線程A沒(méi)在synchronized同步代碼塊了,就執(zhí)行重新偏向了。
小陳:嗯嗯,老王你這么將我就明白了。
小陳:老王啊,我還有個(gè)問(wèn)題,就是如果線程B在申請(qǐng)獲取鎖的時(shí)候,線程A這哥們還沒(méi)執(zhí)行完synchronized同步代碼塊怎么辦?
老王:這個(gè)時(shí)候就有鎖的競(jìng)爭(zhēng)了,這就需要將鎖升級(jí)一下了,線程B就會(huì)把鎖升級(jí)為輕量級(jí)鎖?
偏向鎖為什么要升級(jí)為輕量級(jí)鎖?
小陳:為啥啊,都使用偏向鎖不行嗎?不升級(jí)有什么壞處?
老王:下面給你講原因,先給你看下如下代碼塊:
// 代碼塊1 synchronized(this){// 業(yè)務(wù)代碼1 } // 代碼塊2 synchronized(this){// 業(yè)務(wù)代碼2 } // 代碼塊3 synchronized(this){// 業(yè)務(wù)代碼3 } // 代碼塊4 synchronized(this){// 業(yè)務(wù)代碼4 }假如這個(gè)時(shí)候有線程A、B、C、D四個(gè)線程,線程A先加了偏向鎖。之前講過(guò)偏向鎖只是在第一次獲取鎖的時(shí)候加鎖,后面都是直接操作的不需要加鎖。
這個(gè)時(shí)候其它幾個(gè)線程B、C、D想要加鎖,如果線程A連續(xù)執(zhí)行上面4個(gè)代碼塊,那么其他線程看到線程A都在執(zhí)行synchronized同步代碼塊,沒(méi)完沒(méi)了了,想重偏向都不行!!,這個(gè)時(shí)候就需要等線程A執(zhí)行完4個(gè)synchronized代碼塊之后才能獲取鎖啊,哈哈,別的線程都只能看線程A一個(gè)人自己在那表演了,這樣代碼就變成串行執(zhí)行了。
小陳:原來(lái)是在這樣啊...,也就是說(shuō)如果不進(jìn)行升級(jí),就會(huì)存在這種問(wèn)題,明白了。
老王:這下子多個(gè)線程競(jìng)爭(zhēng)鎖的時(shí)候?yàn)槭裁匆?jí)明白了吧?
小陳:懂了懂......
老王:下面我們進(jìn)入鎖升級(jí)的第一個(gè)級(jí)別,輕量級(jí)鎖,講之前,先回顧之前將的一個(gè)知識(shí)點(diǎn):
輕量級(jí)鎖
輕量級(jí)鎖模式下,加鎖之前會(huì)創(chuàng)建一個(gè)鎖記錄,然后將Mark Word中的數(shù)據(jù)備份到鎖記錄中(Mark Word存儲(chǔ)hashcode、GC年齡等很重要數(shù)據(jù),不能丟失了),以便后續(xù)恢復(fù)Mark Word使用。
這個(gè)鎖記錄放在加鎖線程的虛擬機(jī)棧中,加鎖的過(guò)程就是將Mark Word 前面的30位指向鎖記錄地址。所以mark word的這個(gè)地址指向哪個(gè)線程的虛擬機(jī)棧中,就說(shuō)明哪個(gè)線程獲取了輕量級(jí)鎖。
小陳:嗯嗯,這個(gè)我了解,之前我們?cè)谇懊娴奈恼吕锩嬗懻撨^(guò)。
老王:好的,既然你了解我就放心了,記得如果不了解的話需要看一下之前講過(guò)的文章哦......
老王:就好比下面的圖,線程A獲取了輕量級(jí)鎖,鎖記錄存在線程A的虛擬機(jī)棧中,然后Mark Word的前面30位存儲(chǔ)鎖記錄的地址。
老王:了解了輕量級(jí)加鎖的原理之后,我們繼續(xù),來(lái)講講偏向鎖升級(jí)為輕量級(jí)鎖的過(guò)程:
(1)首先線程A持有偏向鎖,然后正在執(zhí)行synchronized塊中的代碼
(2)這個(gè)時(shí)候線程B來(lái)競(jìng)爭(zhēng)鎖,發(fā)現(xiàn)有人加了偏向鎖并且正在執(zhí)行synchronized塊中的代碼,為了避免上述說(shuō)的線程A一直持有鎖不釋放的情況,需要對(duì)鎖進(jìn)行升級(jí),升級(jí)為輕量級(jí)鎖
(3)先將線程A暫停,為線程A創(chuàng)建一個(gè)鎖記錄Lock Record,將Mark Word的數(shù)據(jù)復(fù)制到鎖記錄中;然后將鎖記錄放入線程A的虛擬機(jī)棧中
(4)然后將Mark Word中的前30位指向線程A中鎖記錄的地址,將線程A喚醒,線程A就知道自己持有了輕量級(jí)鎖
老王:上面就是偏向鎖升級(jí)為輕量級(jí)鎖的過(guò)程,小陳你看明白了嗎?
小陳:等等,我再消化一下,10分鐘過(guò)后.....(再重新看一遍)
小陳:老王,你說(shuō)的這個(gè)偏向鎖升級(jí)輕量級(jí)鎖的過(guò)程我看懂了...
小陳:老王啊,上面偏向鎖升級(jí)為輕量級(jí)鎖的過(guò)程和原理我了解了,那在輕量級(jí)鎖模式下,多線程是怎么競(jìng)爭(zhēng)鎖和釋放鎖的?
老王:我再慢慢給你講解下:
(1)線程A和線程B同時(shí)競(jìng)爭(zhēng)鎖,在輕量級(jí)鎖模式下,都會(huì)創(chuàng)建Lock Record鎖記錄放入自己的棧幀中
(2)同時(shí)執(zhí)行CAS操作,將Mark Word前30位設(shè)置為自己鎖記錄的地址,誰(shuí)設(shè)置成功了,鎖就獲取到鎖
老王:上面講了加鎖的過(guò)程,輕量級(jí)鎖的釋放很簡(jiǎn)單,就將自己的Lock Record中的Mark Word備份的數(shù)據(jù)恢復(fù)回去即可,恢復(fù)的時(shí)候執(zhí)行的是CAS操作將Mark Word數(shù)據(jù)恢復(fù)成加鎖前的樣子。
老王:這個(gè)輕量級(jí)鎖的加鎖和釋放鎖原理懂了沒(méi)?
小陳:嗯嗯,清晰明了了,老王真棒......
老王:好了看看時(shí)間,差不多九點(diǎn)半了,講完最后一個(gè)輕量級(jí)鎖升級(jí)為重量級(jí)鎖就差不多下班了
重量級(jí)鎖的自旋
老王:小陳啊,你想想,在輕量級(jí)鎖模式下獲取鎖失敗的線程應(yīng)該會(huì)怎么樣?
小陳:獲取鎖失敗的線程應(yīng)該會(huì)再去嘗試吧?或者直接沉睡等待別人釋放鎖的時(shí)候?qū)⑺鼏拘?#xff1f;
老王:你說(shuō)的兩種其實(shí)都有可能,但是你覺(jué)得哪種花銷(xiāo)會(huì)更小一點(diǎn)?
小陳:我覺(jué)得線程沉睡花費(fèi)代價(jià)更大吧,這涉及到上下文切換,操作系統(tǒng)層次涉及到用戶態(tài)轉(zhuǎn)內(nèi)核態(tài),是一個(gè)非常重的操作。
老王:你說(shuō)的沒(méi)錯(cuò),既然線程沉睡和喚醒代價(jià)這么大,所以肯定是不會(huì)讓線程輕易就沉睡的;
比如說(shuō)線程沉睡再喚醒最少需要3000ms的時(shí)間,如果某個(gè)線程只使用鎖150ms的時(shí)間就釋放了,如果直接采用沉睡方式的話,這個(gè)時(shí)候synchronized的性能就太差了。
所以啊JVM的設(shè)計(jì)者,設(shè)計(jì)了一種方案,獲取鎖失敗之后的線程自己先原地等一段時(shí)間,然后再去重試獲取鎖,這種方式就叫做自旋。
小陳:但是JVM怎么知道要等多久呢,加入持有鎖的那個(gè)人一直不釋放鎖,其他人要一直自旋等待,然后不斷重復(fù)嘗試嗎?這樣不是非常消耗CPU的資源的嗎?
老王:這里自旋多少次是有一個(gè)限制的,之前我們講解monitor的底層原理的時(shí)候就講解過(guò)了,如果忘記的話可以回去重新看一下。
monitor有一個(gè)_spinFreq參數(shù)表示最大自旋的次數(shù),_spinClock參數(shù)表示自旋的間隔時(shí)間。所以自旋最多會(huì)重試_spinFreq次,每次失敗之后等_spinClock的時(shí)間過(guò)后再去重試,如果嘗試_spinFreq次之后都沒(méi)有成功,那沒(méi)轍了,只能沉睡了。
老王:自旋其實(shí)是非常消耗CPU資源的,自旋期間相當(dāng)于CPU啥也不干,就在那等著的。為了避免自旋時(shí)間太長(zhǎng),所以JVM就規(guī)定了默認(rèn)最多自旋10次,10次還獲取不到鎖,那就直接將線程掛起了,線程就會(huì)直接阻塞等待了,這個(gè)時(shí)候性能就差了。
老王:小陳啊,關(guān)于這個(gè)重量級(jí)鎖下的自旋過(guò)程,你清楚了沒(méi)?
小陳:嗯嗯,非常了解了,老王牛逼......
總結(jié)
總的來(lái)說(shuō)啊,JVM設(shè)計(jì)的這套synchronized鎖升級(jí)的原則,主要是為了花費(fèi)最小的代價(jià)能達(dá)到加鎖的目的;
比如在沒(méi)有競(jìng)爭(zhēng)的情況下,進(jìn)入synchronized的使用使用偏向鎖就夠了,這樣只需要第一次執(zhí)行CAS操作獲取鎖,獲取了偏向鎖之后,后面每次進(jìn)入synchronized同步代碼塊就不需要再次加鎖了。
然后在存在多個(gè)線程競(jìng)爭(zhēng)鎖的時(shí)候就不能使用偏向鎖了,不能只偏心一個(gè)人,它優(yōu)先獲取鎖,別人都看它表演,這樣是不行的。
于是就升級(jí)為輕量級(jí)鎖,在輕量級(jí)鎖模式在每次加鎖和釋放是都需要執(zhí)行CAS操作,對(duì)比偏向鎖來(lái)說(shuō)性能低一點(diǎn)的,但是總體還是比較輕量級(jí)的。
為了盡量提升線程獲取鎖的機(jī)會(huì),避免線程陷入獲取鎖失敗就立即沉睡的局面(線程沉睡再喚醒涉及上下文切換,用戶態(tài)內(nèi)核態(tài)切換,是一個(gè)非常重的操作,很費(fèi)時(shí)間),所以設(shè)計(jì)自旋等待;線程每次自旋一段時(shí)間之后再去重試獲取鎖。
當(dāng)競(jìng)爭(zhēng)非常激烈,并發(fā)很高,或者是synchronized代碼塊執(zhí)行耗時(shí)比較長(zhǎng),就會(huì)積壓大量的線程都在自旋,由于自旋是空耗費(fèi)CPU資源的,也就是CPU在那等著,做不了其他事情,所以在嘗試了最大的自旋次數(shù)之后;及時(shí)釋放CPU資源,將線程掛起了。
老王:總的來(lái)說(shuō)synchronized升級(jí)的原理就是這樣了?
小陳:嗯嗯,講解的非常詳細(xì)了,真棒......
老王:好了,本章的講解就到這里了,synchronized也講解的差不多了,下一章最后講解一下synchronized保證并發(fā)安全的可見(jiàn)性、有序性、原子性是怎么做到的?
那么我們這個(gè)《練氣篇》就差不多了,學(xué)完這一篇之后,你會(huì)發(fā)現(xiàn)對(duì)volatile、synchronized的了解更加深入了,在并發(fā)底層保證了什么,怎么做到了?相信你學(xué)完這一篇之后,功力就會(huì)更加不少咯。
小陳:好的,老王,我們下一章見(jiàn)。
關(guān)注小陳,公眾號(hào)上更多更全的文章
JAVA并發(fā)文章目錄(公眾號(hào))
JAVA并發(fā)專(zhuān)題 《筑基篇》
1.什么是CPU多級(jí)緩存模型?
2.什么是JAVA內(nèi)存模型?
3.線程安全之可見(jiàn)性、有序性、原子性是什么?
4.什么是MESI緩存一致性協(xié)議?怎么解決并發(fā)的可見(jiàn)性問(wèn)題?
JAVA并發(fā)專(zhuān)題《練氣篇》
5.volatile怎么保證可見(jiàn)性?
6.什么是內(nèi)存屏障?具有什么作用?
7.volatile怎么通過(guò)內(nèi)存屏障保證可見(jiàn)性和有序性?
8.volatile為啥不能保證原子性?
9.synchronized是個(gè)啥東西?應(yīng)該怎么使用?
10.synchronized底層之monitor、對(duì)象頭、Mark Word?
11.synchronized底層是怎么通過(guò)monitor進(jìn)行加鎖的?
12.synchronized的鎖重入、鎖消除、鎖升級(jí)原理?無(wú)鎖、偏向鎖、輕量級(jí)鎖、自旋、重量級(jí)鎖
13.synchronized怎么保證可見(jiàn)性、有序性、原子性?
JAVA并發(fā)專(zhuān)題《結(jié)丹篇》
14. JDK底層Unsafe類(lèi)是個(gè)啥東西?
15.unsafe類(lèi)的CAS是怎么保證原子性的?
16.Atomic原子類(lèi)體系講解
17.AtomicInteger、AtomicBoolean的底層原理
18.AtomicReference、AtomicStampReference底層原理
19.Atomic中的LongAdder底層原理之分段鎖機(jī)制
20.Atmoic系列Strimped64分段鎖底層實(shí)現(xiàn)源碼剖析
JAVA并發(fā)專(zhuān)題《金丹篇》
21.AQS是個(gè)啥?為啥說(shuō)它是JAVA并發(fā)工具基礎(chǔ)框架?
22.基于AQS的互斥鎖底層源碼深度剖析
23.基于AQS的共享鎖底層源碼深度剖析
24.ReentrantLock是怎么基于AQS實(shí)現(xiàn)獨(dú)占鎖的?
25.ReentrantLock的Condition機(jī)制底層源碼剖析
26.CountDownLatch 門(mén)栓底層源碼和實(shí)現(xiàn)機(jī)制深度剖析
27.CyclicBarrier 柵欄底層源碼和實(shí)現(xiàn)機(jī)制深度剖析
28.Semaphore 信號(hào)量底層源碼和實(shí)現(xiàn)機(jī)深度剖析
29.ReentrantReadWriteLock 讀寫(xiě)鎖怎么表示?
30. ReentrantReadWriteLock 讀寫(xiě)鎖底層源碼和機(jī)制深度剖析
JAVA并發(fā)專(zhuān)題《元神篇》并發(fā)數(shù)據(jù)結(jié)構(gòu)篇
31.CopyOnAarrayList 底層分析,怎么通過(guò)寫(xiě)時(shí)復(fù)制副本,提升并發(fā)性能?
32.ConcurrentLinkedQueue 底層分析,CAS 無(wú)鎖化操作提升并發(fā)性能?
33.ConcurrentHashMap詳解,底層怎么通過(guò)分段鎖提升并發(fā)性能?
34.LinkedBlockedQueue 阻塞隊(duì)列怎么通過(guò)ReentrantLock和Condition實(shí)現(xiàn)?
35.ArrayBlockedQueued 阻塞隊(duì)列實(shí)現(xiàn)思路竟然和LinkedBlockedQueue一樣?
36.DelayQueue 底層源碼剖析,延時(shí)隊(duì)列怎么實(shí)現(xiàn)?
37.SynchronousQueue底層原理解析
JAVA并發(fā)專(zhuān)題《飛升篇》線程池底層深度剖析
38. 什么是線程池?看看JDK提供了哪些默認(rèn)的線程池?底層竟然都是基于ThreadPoolExecutor的?
39.ThreadPoolExecutor 構(gòu)造函數(shù)有哪些參數(shù)?這些參數(shù)分別表示什么意思?
40.內(nèi)部有哪些變量,怎么表示線程池狀態(tài)和線程數(shù),看看道格.李大神是怎么設(shè)計(jì)的?
41. ThreadPoolExecutor execute執(zhí)行流程?怎么進(jìn)行任務(wù)提交的?addWorker方法干了啥?什么是workder?
42. ThreadPoolExecutor execute執(zhí)行流程?何時(shí)將任務(wù)提交到阻塞隊(duì)列? 阻塞隊(duì)列滿會(huì)發(fā)生什么?
43. ThreadPoolExecutor 中的Worker是如何執(zhí)行提交到線程池的任務(wù)的?多余Worker怎么在超出空閑時(shí)間后被干掉的?
44. ThreadPoolExecutor shutdown、shutdownNow內(nèi)部核心流程
45. 再回頭看看為啥不推薦Executors提供幾種線程池?
46. ThreadPoolExecutor線程池篇總結(jié)
總結(jié)
以上是生活随笔為你收集整理的12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 免费pdf转换器软件
- 下一篇: 唐山新维计算机学校,WellDesign