您好,登錄后才能下訂單哦!
小編給大家分享一下Java多線程之死鎖的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
什么是死鎖?
死鎖是這樣一種情形:多個線程同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放.由于線程被無限期地阻塞,因此程序不能正常運行.形象的說就是:一個寶藏需要兩把鑰匙來打開,同時間正好來了兩個人,他們一人一把鑰匙,但是雙方都再等著對方能交出鑰匙來打開寶藏,誰都沒釋放自己的那把鑰匙.就這樣這倆人一直僵持下去,直到開發(fā)人員發(fā)現(xiàn)這個局面.
導致死鎖的根源在于不適當?shù)剡\用“synchronized”關鍵詞來管理線程對特定對象的訪問.“synchronized”關鍵詞的作用是,確保在某個時刻只有一個線程被允許執(zhí)行特定的代碼塊,因此,被允許執(zhí)行的線程首先必須擁有對變量或?qū)ο蟮呐潘栽L問權(quán).當線程訪問對象時,線程會給對象加鎖,而這個鎖導致其它也想訪問同一對象的線程被阻塞,直至第一個線程釋放它加在對象上的鎖.
對synchronized不太了解的話請點擊這里
舉個例子
死鎖的產(chǎn)生大部分都是在你不知情的時候.我們通過一個例子來看下什么是死鎖.
1.synchronized嵌套.
synchronized關鍵字可以保證多線程再訪問到synchronized修飾的方法的時候保證了同步性.就是線程A訪問到這個方法的時候線程B同時也來訪問這個方法,這時線程B將進行阻塞,等待線程A執(zhí)行完才可以去訪問.這里就要用到synchronized所持有的同步鎖.具體來看代碼:
//首先我們先定義兩個final的對象鎖.可以看做是共有的資源. final Object lockA = new Object(); final Object lockB = new Object(); //生產(chǎn)者A class ProductThreadA implements Runnable{ @Override public void run() { //這里一定要讓線程睡一會兒來模擬處理數(shù)據(jù) ,要不然的話死鎖的現(xiàn)象不會那么的明顯.這里就是同步語句塊里面,首先獲得對象鎖lockA,然后執(zhí)行一些代碼,隨后我們需要對象鎖lockB去執(zhí)行另外一些代碼. synchronized (lockA){ //這里一個log日志 Log.e("CHAO","ThreadA lock lockA"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockB){ //這里一個log日志 Log.e("CHAO","ThreadA lock lockB"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } //生產(chǎn)者B class ProductThreadB implements Runnable{ //我們生產(chǎn)的順序真好好生產(chǎn)者A相反,我們首先需要對象鎖lockB,然后需要對象鎖lockA. @Override public void run() { synchronized (lockB){ //這里一個log日志 Log.e("CHAO","ThreadB lock lockB"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockA){ //這里一個log日志 Log.e("CHAO","ThreadB lock lockA"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } //這里運行線程 ProductThreadA productThreadA = new ProductThreadA(); ProductThreadB productThreadB = new ProductThreadB(); Thread threadA = new Thread(productThreadA); Thread threadB = new Thread(productThreadB); threadA.start(); threadB.start();
分析一下,當threadA開始執(zhí)行run方法的時候,它會先持有對象鎖localA,然后睡眠2秒,這時候threadB也開始執(zhí)行run方法,它持有的是localB對象鎖.當threadA運行到第二個同步方法的時候,發(fā)現(xiàn)localB的對象鎖不能使用(threadB未釋放localB鎖),threadA就停在這里等待localB鎖.隨后threadB也執(zhí)行到第二個同步方法,去訪問localA對象鎖的時候發(fā)現(xiàn)localA還沒有被釋放(threadA未釋放localA鎖),threadB也停在這里等待localA鎖釋放.就這樣兩個線程都沒辦法繼續(xù)執(zhí)行下去,進入死鎖的狀態(tài). 看下運行結(jié)果:
10-20 14:54:39.940 18162-18178/? E/CHAO: ThreadA lock lockA 10-20 14:54:39.940 18162-18179/? E/CHAO: ThreadB lock lockB
當不會死鎖的時候應該是打印四條log的,這里明顯的出現(xiàn)了死鎖的現(xiàn)象.
死鎖出現(xiàn)的原因
當我們了解在什么情況下會產(chǎn)生死鎖,以及什么是死鎖的時候,我們在寫代碼的時候應該盡量的去避免這個誤區(qū).產(chǎn)生死鎖必須同時滿足以下四個條件,只要其中任一條件不成立,死鎖就不會發(fā)生.
互斥條件:線程要求對所分配的資源進行排他性控制,即在一段時間內(nèi)某 資源僅為一個進程所占有.此時若有其他進程請求該資源.則請求進程只能等待.
不剝奪條件:進程所獲得的資源在未使用完畢之前,不能被其他進程強行奪走,即只能由獲得該資源的線程自己來釋放(只能是主動釋放).
請求和保持條件:線程已經(jīng)保持了至少一個資源,但又提出了新的資源請求,而該資源已被其他線程占有,此時請求線程被阻塞,但對自己已獲得的資源保持不放.
循環(huán)等待條件:存在一種線程資源的循環(huán)等待鏈,鏈中每一個線程已獲得的資源同時被鏈中下一個線程所請求。
死鎖的解決方法
說實話避免死鎖還得再自己寫代碼的時候注意一下.這里引用別人的解決方法,不過我對于這些解決方法不是太懂,講的太含糊沒有具體的實例.
以上是“Java多線程之死鎖的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業(yè)資訊頻道!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。