小黑有點(diǎn)困,他想休息,又怕耽誤時(shí)間,于是準(zhǔn)備小瞇一會(huì)。
為了能按時(shí)起來(lái),他設(shè)了鬧鐘,作為程序員,必須得整兩個(gè),防止單點(diǎn)故障。
當(dāng)任意一個(gè)鬧鐘響起,小黑就起來(lái)把兩個(gè)鬧鐘都關(guān)掉,繼續(xù)干活,就像這樣:
public class Clock { private BlackBro blackBro; public void setBlackBro(BlackBro blackBro) { this.blackBro = blackBro; } public synchronized void ring() { System.out.println(Thread.currentThread() + " Clock.ring..."); blackBro.wake(); } public synchronized void close() { System.out.println(Thread.currentThread() + " Clock.close..."); }}
public class BlackBro { private Clock[] clocks; public void setClocks(Clock[] clocks) { this.clocks = clocks; } public synchronized void wake() { System.out.println(Thread.currentThread() + "BlackBro.wake..."); for (Clock clock : clocks) { clock.close(); } }}
為了防止鬧鐘和小黑在執(zhí)行操作期間被人打擾,我貼心地給他們都加上了鎖 —— synchronized。
模擬這個(gè)場(chǎng)景將是這樣:
public static void main(String[] args) { Clock clock1 = new Clock(); Clock clock2 = new Clock(); BlackBro blackBro = new BlackBro(); clock1.setBlackBro(blackBro); clock2.setBlackBro(blackBro); blackBro.setClocks(new Clock[]{clock1, clock2}); // sleep... Thread t1 = new Thread(clock1::ring); Thread t2 = new Thread(clock2::ring); t1.start(); t2.start();}
啟動(dòng)程序發(fā)現(xiàn),陷入了無(wú)盡地等待:
Thread[Thread-0,5,main] Clock.ring...Thread[Thread-1,5,main] Clock.ring...Thread[Thread-1,5,main]BlackBro.wake...
這是怎么回事?眼尖的同學(xué)肯定發(fā)現(xiàn)問(wèn)題了。我們看一下 jstack:
Found one Java-level deadlock:============================="Thread-0": waiting to lock monitor 0x0000600003ecc000 (object 0x000000070fc52398, a com.demo.BlackBro), which is held by "Thread-1""Thread-1": waiting to lock monitor 0x0000600003ec04e0 (object 0x000000070fc50f88, a com.demo.Clock), which is held by "Thread-0"Java stack information for the threads listed above:===================================================
原來(lái)是死鎖了:我們起了兩個(gè)鬧鐘線程,兩個(gè)線程各自拿到自己的對(duì)象鎖,開(kāi)始 ring,ring 又都會(huì)去喚醒小黑,但小黑對(duì)象只有一個(gè),只有一個(gè)鬧鐘能順利拿到小黑的對(duì)象鎖,小黑被喚醒后又去關(guān)鬧鐘,但卻沒(méi)法關(guān)掉,因?yàn)轸[鐘在等小黑喚醒的期間不會(huì)被別人打斷,于是鬧鐘在等小黑,小黑在等鬧鐘,形成了死鎖。
我相信稍微仔細(xì)點(diǎn)大家都能發(fā)現(xiàn)這個(gè)問(wèn)題,這是因?yàn)槲野迅蓴_項(xiàng)都排除,只留下非常簡(jiǎn)單的框架。如果在一個(gè)非常復(fù)雜的系統(tǒng)中,還是很難發(fā)現(xiàn)的。這也是我今天遇到的一個(gè)線上問(wèn)題,花了半天時(shí)間才排查出來(lái)。
這個(gè) case 教育我們要謹(jǐn)慎使用鎖,尤其是 synchronized;其次如果發(fā)現(xiàn)程序沒(méi)有按預(yù)期地執(zhí)行,尤其是該執(zhí)行的沒(méi)執(zhí)行,可以留個(gè)心眼,看看堆棧是不是有死鎖。
2024 年第一個(gè)小case送給你,你學(xué)廢了嗎?
本文鏈接:http://www.www897cc.com/showinfo-26-64969-0.html為了讓小白也能看懂這個(gè)死鎖Case,我請(qǐng)來(lái)了小黑...
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com