摘要:本人郵箱歡迎轉(zhuǎn)載轉(zhuǎn)載請(qǐng)注明網(wǎng)址代碼已經(jīng)全部托管有需要的同學(xué)自行下載引言多線(xiàn)程如果設(shè)計(jì)的不合理的話(huà)很可能就會(huì)出現(xiàn)死鎖當(dāng)兩個(gè)或者多個(gè)線(xiàn)程同事想要去獲取共享資源的鎖時(shí)但每個(gè)線(xiàn)程都要等其他線(xiàn)程把他們各自的鎖給釋放才能繼續(xù)運(yùn)行這就是死鎖出現(xiàn)死鎖必須具
引言本人郵箱:
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明網(wǎng)址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經(jīng)全部托管github有需要的同學(xué)自行下載
多線(xiàn)程如果設(shè)計(jì)的不合理的話(huà),很可能就會(huì)出現(xiàn)死鎖.當(dāng)兩個(gè)或者多個(gè)線(xiàn)程同事想要去獲取共享資源的鎖時(shí),但每個(gè)線(xiàn)程都要等其他線(xiàn)程把他們各自的鎖給釋放,才能繼續(xù)運(yùn)行,這就是死鎖.出現(xiàn)死鎖必須具備以下幾點(diǎn)
要有兩個(gè)或兩個(gè)以上的線(xiàn)程
至少有兩個(gè)共享資源的鎖
至少存在兩個(gè)線(xiàn)程各自擁有一個(gè)鎖
現(xiàn)在這兩個(gè)線(xiàn)程在等待獲取彼此的鎖,這就出現(xiàn)死鎖了
比如Thread1
synchronized(A){ //Thread1 執(zhí)行到這里 synchronized(B){ ... } }
Thread2
synchronized(B){ //Thread2 執(zhí)行到這里 synchronized(A){ ... } }
以上這種情況就是死鎖,如果是兩個(gè)線(xiàn)程出現(xiàn)死鎖,問(wèn)題可能還比較好找.更復(fù)雜是有多個(gè)線(xiàn)程,比如線(xiàn)程n各自擁有鎖n,然后線(xiàn)程1到線(xiàn)程n-1,正在請(qǐng)求獲取鎖n+1,而線(xiàn)程n正在請(qǐng)求獲取鎖1,這樣也或出現(xiàn)死鎖,而且還更難被發(fā)現(xiàn).
例子我們要看一個(gè)例子
public class Demo1 { public static void main(String[] args) { Object bigGate = new Object(); Object smallGate = new Object(); new Thread(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); synchronized (bigGate){ System.out.println(name + ":我把大門(mén)給鎖了...然后我休息一下..."); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + ":我現(xiàn)在要進(jìn)入小門(mén)....."); synchronized (smallGate){ System.out.println(name + ":我永遠(yuǎn)都進(jìn)不來(lái)啊....."); } } } },"小明").start(); new Thread(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); synchronized (smallGate){ System.out.println(name + ":我把小門(mén)給鎖了...然后我休息一下..."); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + ":我現(xiàn)在要進(jìn)入大門(mén)....."); synchronized (bigGate){ System.out.println(name + ":我永遠(yuǎn)都進(jìn)不來(lái)啊....."); } } } },"小紅").start(); } }
運(yùn)行結(jié)果
小明我把大門(mén)給鎖了...然后我休息一下... 小紅我把小門(mén)給鎖了...然后我休息一下... 小明:我現(xiàn)在要進(jìn)入小門(mén)..... 小紅:我現(xiàn)在要進(jìn)入大門(mén)..... //然后程序到這里就一直不動(dòng)了.....解決辦法
鎖的順序,讓兩個(gè)線(xiàn)程獲取鎖的順序是一直,則不會(huì)出現(xiàn)死鎖
public class Demo2 { public static void main(String[] args) { Object bigGate = new Object(); Object smallGate = new Object(); new Thread(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); synchronized (bigGate){ System.out.println(name + ":我把大門(mén)給鎖了...然后我休息一下..."); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + ":我現(xiàn)在要進(jìn)入小門(mén)....."); synchronized (smallGate){ System.out.println(name + ":我終于進(jìn)來(lái)了....."); } } } },"小明").start(); new Thread(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); synchronized (bigGate){ System.out.println(name + ":我把大門(mén)給鎖了...然后我休息一下..."); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + ":我現(xiàn)在要進(jìn)入小門(mén)....."); synchronized (smallGate){ System.out.println(name + ":我終于進(jìn)來(lái)了....."); } } } },"小紅").start(); } }
運(yùn)行結(jié)果:
小明:我把大門(mén)給鎖了...然后我休息一下... 小明:我現(xiàn)在要進(jìn)入小門(mén)..... 小明:我終于進(jìn)來(lái)了..... 小紅:我把大門(mén)給鎖了...然后我休息一下... 小紅:我現(xiàn)在要進(jìn)入小門(mén)..... 小紅:我終于進(jìn)來(lái)了.....
在獲取鎖的時(shí)候加超時(shí)時(shí)間,這里我們用之前學(xué)的Lock來(lái)做例子
public class Demo3 { public static void main(String[] args) { Lock bigGate = new ReentrantLock(); Lock smallGate = new ReentrantLock(); Random random = new Random(); new Thread(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); bigGate.lock(); try { System.out.println(name + ":我把大門(mén)給鎖了...然后我休息一下..."); Thread.sleep(100); System.out.println(name + ":我現(xiàn)在要進(jìn)入小門(mén)....."); if(smallGate.tryLock(random.nextInt(500), TimeUnit.MILLISECONDS)){ try { System.out.println(name + ":我終于進(jìn)來(lái)了....."); }finally { smallGate.unlock(); } }else{ System.out.println(name + ":我進(jìn)不去小門(mén),算了,不進(jìn)了..."); } } catch (InterruptedException e) { e.printStackTrace(); } finally { bigGate.unlock(); } } },"小明").start(); new Thread(new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); smallGate.lock(); try { System.out.println(name + ":我把小門(mén)給鎖了...然后我休息一下..."); Thread.sleep(100); System.out.println(name + ":我現(xiàn)在要進(jìn)入大門(mén)....."); if(bigGate.tryLock(random.nextInt(500), TimeUnit.MILLISECONDS)){ try { System.out.println(name + ":我終于進(jìn)來(lái)了....."); }finally { bigGate.unlock(); } }else{ System.out.println(name + ":我進(jìn)不去大門(mén),算了,不進(jìn)了..."); } } catch (InterruptedException e) { e.printStackTrace(); } finally { smallGate.unlock(); } } },"小紅").start(); } }
運(yùn)行結(jié)果:
小明:我把大門(mén)給鎖了...然后我休息一下... 小紅:我把小門(mén)給鎖了...然后我休息一下... 小明:我現(xiàn)在要進(jìn)入小門(mén)..... 小紅:我現(xiàn)在要進(jìn)入大門(mén)..... 小紅:我進(jìn)不去大門(mén),算了,不進(jìn)了... 小明:我終于進(jìn)來(lái)了.....
這樣也可以保證不會(huì)出現(xiàn)死鎖.
打賞如果覺(jué)得我的文章寫(xiě)的還過(guò)得去的話(huà),有錢(qián)就捧個(gè)錢(qián)場(chǎng),沒(méi)錢(qián)給我捧個(gè)人場(chǎng)(幫我點(diǎn)贊或推薦一下)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67041.html
摘要:超詳細(xì)的面試題總結(jié)一之基本知識(shí)多線(xiàn)程和虛擬機(jī)創(chuàng)建線(xiàn)程有幾種不同的方式你喜歡哪一種為什么繼承類(lèi)實(shí)現(xiàn)接口應(yīng)用程序可以使用框架來(lái)創(chuàng)建線(xiàn)程池實(shí)現(xiàn)接口。死亡線(xiàn)程方法執(zhí)行結(jié)束,或者因異常退出了方法,則該線(xiàn)程結(jié)束生命周期。死亡的線(xiàn)程不可再次復(fù)生。 超詳細(xì)的Java面試題總結(jié)(一)之Java基本知識(shí) 多線(xiàn)程和Java虛擬機(jī) 創(chuàng)建線(xiàn)程有幾種不同的方式?你喜歡哪一種?為什么? 繼承Thread類(lèi) 實(shí)現(xiàn)R...
摘要:我的是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)。因?yàn)槲倚睦砗芮宄?,我的目?biāo)是阿里。所以在收到阿里之后的那晚,我重新規(guī)劃了接下來(lái)的學(xué)習(xí)計(jì)劃,將我的短期目標(biāo)更新成拿下阿里轉(zhuǎn)正。 我的2017是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕JDK源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)offer。然后五月懷著忐忑的心情開(kāi)始了螞蟻金...
摘要:此時(shí)線(xiàn)程需要鎖才能繼續(xù)往下執(zhí)行。但是線(xiàn)程的鎖并沒(méi)有釋放,線(xiàn)程的鎖也沒(méi)有釋放。 前言 只有光頭才能變強(qiáng) 回顧前面: ThreadLocal就是這么簡(jiǎn)單 多線(xiàn)程三分鐘就可以入個(gè)門(mén)了! 多線(xiàn)程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)多線(xiàn)程事半功倍 Java鎖機(jī)制了解一下 AQS簡(jiǎn)簡(jiǎn)單單過(guò)一遍 Lock鎖子類(lèi)了解一下 線(xiàn)程池你真不來(lái)了解一下嗎? 本篇主要是講解死鎖,這是我在多線(xiàn)程的最后一篇了。主要將多線(xiàn)程...
摘要:但是,有些操作會(huì)依賴(lài)于對(duì)象的變化過(guò)程,此時(shí)的解決思路一般就是使用版本號(hào)。在變量前面追加上版本號(hào),每次變量更新的時(shí)候把版本號(hào)加一,那么就會(huì)變成。四的引入就是上面所說(shuō)的加了版本號(hào)的。 showImg(https://segmentfault.com/img/remote/1460000016012188); 本文首發(fā)于一世流云的專(zhuān)欄:https://segmentfault.com/blo...
摘要:線(xiàn)程間通信其實(shí)就是多個(gè)線(xiàn)程操作同一個(gè)資源,但動(dòng)作不同。同步前提是多線(xiàn)程。將該線(xiàn)程載入線(xiàn)程池,等待喚醒。該方法拋出異常,故需要配合使用隨機(jī)喚醒線(xiàn)程池中一線(xiàn)程。線(xiàn)程為了檢測(cè)死鎖,它需要遞進(jìn)地檢測(cè)所有被請(qǐng)求的鎖。 線(xiàn)程間通信 其實(shí)就是多個(gè)線(xiàn)程操作同一個(gè)資源,但動(dòng)作不同。示例:在某個(gè)數(shù)據(jù)庫(kù)中,Input輸入人的姓名,性別,Output輸出,兩個(gè)線(xiàn)程同時(shí)作用。思考:1.明確哪些代碼是多線(xiàn)程操作的...
閱讀 1219·2021-11-22 12:05
閱讀 1344·2021-09-29 09:35
閱讀 640·2019-08-30 15:55
閱讀 3135·2019-08-30 14:12
閱讀 961·2019-08-30 14:11
閱讀 2882·2019-08-30 13:10
閱讀 2411·2019-08-29 16:33
閱讀 3338·2019-08-29 11:02