Java多線程-死鎖html
什麼是死鎖?git
死鎖是這樣一種情形:多個線程同時被阻塞,它們中的一個或者所有都在等待某個資源被釋放.因爲線程被無限期地阻塞,所以程序不能正常運行.形象的說就是:一個寶藏須要兩把鑰匙來打開,同時間正好來了兩我的,他們一人一把鑰匙,可是雙方都再等着對方能交出鑰匙來打開寶藏,誰都沒釋放本身的那把鑰匙.就這樣這倆人一直僵持下去,直到開發人員發現這個局面.github
致使死鎖的根源在於不適當地運用「synchronized」關鍵詞來管理線程對特定對象的訪問.「synchronized」關鍵詞的做用是,確保在某個時刻只有一個線程被容許執行特定的代碼塊,所以,被容許執行的線程首先必須擁有對變量或對象的排他性訪問權.當線程訪問對象時,線程會給對象加鎖,而這個鎖致使其它也想訪問同一對象的線程被阻塞,直至第一個線程釋放它加在對象上的鎖.bash
對synchronized不太瞭解的話請點擊這裏多線程
舉個例子ide
死鎖的產生大部分都是在你不知情的時候.咱們經過一個例子來看下什麼是死鎖.post
1.synchronized嵌套.ui
synchronized關鍵字能夠保證多線程再訪問到synchronized修飾的方法的時候保證了同步性.就是線程A訪問到這個方法的時候線程B同時也來訪問這個方法,這時線程B將進行阻塞,等待線程A執行完才能夠去訪問.這裏就要用到synchronized所持有的同步鎖.具體來看代碼:spa
//首先咱們先定義兩個final的對象鎖.能夠看作是共有的資源.
final Object lockA = new Object();
final Object lockB = new Object();
//生產者A
class ProductThreadA implements Runnable{
@Override
public void run() {
//這裏必定要讓線程睡一下子來模擬處理數據 ,要否則的話死鎖的現象不會那麼的明顯.這裏就是同步語句塊裏面,首先得到對象鎖lockA,而後執行一些代碼,隨後咱們須要對象鎖lockB去執行另一些代碼.
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();
}
}
}
}
}
//生產者B
class ProductThreadB implements Runnable{
//咱們生產的順序真好好生產者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開始執行run方法的時候,它會先持有對象鎖localA,而後睡眠2秒,這時候threadB也開始執行run方法,它持有的是localB對象鎖.當threadA運行到第二個同步方法的時候,發現localB的對象鎖不能使用(threadB未釋放localB鎖),threadA就停在這裏等待localB鎖.隨後threadB也執行到第二個同步方法,去訪問localA對象鎖的時候發現localA尚未被釋放(threadA未釋放localA鎖),threadB也停在這裏等待localA鎖釋放.就這樣兩個線程都沒辦法繼續執行下去,進入死鎖的狀態. 看下運行結果:線程
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的,這裏明顯的出現了死鎖的現象.
死鎖出現的緣由
當咱們瞭解在什麼狀況下會產生死鎖,以及什麼是死鎖的時候,咱們在寫代碼的時候應該儘可能的去避免這個誤區.產生死鎖必須同時知足如下四個條件,只要其中任一條件不成立,死鎖就不會發生.
• 互斥條件:線程要求對所分配的資源進行排他性控制,即在一段時間內某 資源僅爲一個進程所佔有.此時如有其餘進程請求該資源.則請求進程只能等待.
• 不剝奪條件:進程所得到的資源在未使用完畢以前,不能被其餘進程強行奪走,即只能由得到該資源的線程本身來釋放(只能是主動釋放).
• 請求和保持條件:線程已經保持了至少一個資源,但又提出了新的資源請求,而該資源已被其餘線程佔有,此時請求線程被阻塞,但對本身已得到的資源保持不放.
• 循環等待條件:存在一種線程資源的循環等待鏈,鏈中每個線程已得到的資源同時被鏈中下一個線程所請求。
死鎖的解決方法
說實話避免死鎖還得再本身寫代碼的時候注意一下.這裏引用別人的解決方法,不過我對於這些解決方法不是太懂,講的太含糊沒有具體的實例.
歡迎各位吐槽,給個贊吧~