一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳解java中產生死鎖的原因及如何避免

詳解java中產生死鎖的原因及如何避免

2021-07-29 11:16yehao_123456 Java教程

這篇文章主要介紹了java中產生死鎖的原因及如何避免,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

1. java中導致死鎖的原因

java中死鎖最簡單的情況是,一個線程t1持有鎖l1并且申請獲得鎖l2,而另一個線程t2持有鎖l2并且申請獲得鎖l1,因為默認的鎖申請操作都是阻塞的,所以線程t1和t2永遠被阻塞了。導致了死鎖。這是最容易理解也是最簡單的死鎖的形式。但是實際環境中的死鎖往往比這個復雜的多。可能會有多個線程形成了一個死鎖的環路,比如:線程t1持有鎖l1并且申請獲得鎖l2,而線程t2持有鎖l2并且申請獲得鎖l3,而線程t3持有鎖l3并且申請獲得鎖l1,這樣導致了一個鎖依賴的環路:t1依賴t2的鎖l2,t2依賴t3的鎖l3,而t3依賴t1的鎖l1。從而導致了死鎖。

從這兩個例子,我們可以得出結論,產生死鎖可能性的最根本原因是:線程在獲得一個鎖l1的情況下再去申請另外一個鎖l2,也就是鎖l1想要包含了鎖l2,也就是說在獲得了鎖l1,并且沒有釋放鎖l1的情況下,又去申請獲得鎖l2,這個是產生死鎖的最根本原因。另一個原因是默認的鎖申請操作是阻塞的。

2. java中如何避免死鎖

既然我們知道了產生死鎖可能性的原因,那么就可以在編碼時進行規避。java是面向對象的編程語言,程序的最小單元是對象,對象封裝了數據和操作,所以java中的鎖一般也是以對象為單位的,對象的內置鎖保護對象中的數據的并發訪問。所以如果我們能夠避免在對象的同步方法中調用其它對象的同步方法,那么就可以避免死鎖產生的可能性。如下所示的代碼,就存在死鎖的可能性:

?
1
2
3
4
5
6
7
8
9
public class classb {
  private string address;
  // ...
  
  public synchronized void method1(){
    // do something
  }
  // ... ...
}
?
1
2
3
4
5
6
7
8
9
10
11
12
public class classa {
  private int id;
  private string name;
  private classb b;
  // ...
  
  public synchronized void m1(){
    // do something
    b.method1();
  }
  // ... ...
}

上面的classa.m1()方法,在對象的同步方法中又調用了classb的同步方法method1(),所以存在死鎖發生的可能性。我們可以修改如下,避免死鎖:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class classa {
  private int id;
  private string name;
  private classb b;
  // ...
  
  public void m2(){
    synchronized(this){
      // do something
    }
    b.method1();
  }
  // ... ...
}

這樣的話減小了鎖定的范圍,兩個鎖的申請就沒有發生交叉,避免了死鎖的可能性,這是最理性的情況,因為鎖沒有發生交叉。但是有時是不允許我們這樣做的。此時,如果只有classa中只有一個m1這樣的方法,需要同時獲得兩個對象上的鎖,并且不會將實例屬性 b 溢出(return b;),而是將實例屬性 b 封閉在對象中,那么也不會發生死鎖。因為無法形成死鎖的閉環。但是如果classa中有多個方法需要同時獲得兩個對象上的鎖,那么這些方法就必須以相同的順序獲得鎖。

比如銀行轉賬的場景下,我們必須同時獲得兩個賬戶上的鎖,才能進行操作,兩個鎖的申請必須發生交叉。這時我們也可以打破死鎖的那個閉環,在涉及到要同時申請兩個鎖的方法中,總是以相同的順序來申請鎖,比如總是先申請 id 大的賬戶上的鎖 ,然后再申請 id 小的賬戶上的鎖,這樣就無法形成導致死鎖的那個閉環。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class account {
  private int id;  // 主鍵
  private string name;
  private double balance;
  
  public void transfer(account from, account to, double money){
    if(from.getid() > to.getid()){
      synchronized(from){
        synchronized(to){
          // transfer
        }
      }
    }else{
      synchronized(to){
        synchronized(from){
          // transfer
        }
      }
    }
  }
 
  public int getid() {
    return id;
  }
}

這樣的話,即使發生了兩個賬戶比如 id=1的和id=100的兩個賬戶相互轉賬,因為不管是哪個線程先獲得了id=100上的鎖,另外一個線程都不會去獲得id=1上的鎖(因為他沒有獲得id=100上的鎖),只能是哪個線程先獲得id=100上的鎖,哪個線程就先進行轉賬。這里除了使用id之外,如果沒有類似id這樣的屬性可以比較,那么也可以使用對象的hashcode()的值來進行比較。

上面我們說到,死鎖的另一個原因是默認的鎖申請操作是阻塞的,所以如果我們不使用默認阻塞的鎖,也是可以避免死鎖的。我們可以使用reentrantlock.trylock()方法,在一個循環中,如果trylock()返回失敗,那么就釋放以及獲得的鎖,并睡眠一小段時間。這樣就打破了死鎖的閉環。

比如:線程t1持有鎖l1并且申請獲得鎖l2,而線程t2持有鎖l2并且申請獲得鎖l3,而線程t3持有鎖l3并且申請獲得鎖l1

此時如果t3申請鎖l1失敗,那么t3釋放鎖l3,并進行睡眠,那么t2就可以獲得l3了,然后t2執行完之后釋放l2, l3,所以t1也可以獲得l2了執行完然后釋放鎖l1, l2,然后t3睡眠醒來,也可以獲得l1, l3了。打破了死鎖的閉環。

這些情況,都還是比較好處理的,因為它們都是相關的,我們很容易意識到這里有發生死鎖的可能性,從而可以加以防備。很多情況的場景都不會很明顯的讓我們察覺到會存在發生死鎖的可能性。所以我們還是要注意:

一旦我們在一個同步方法中,或者說在一個鎖的保護的范圍中,調用了其它對象的方法時,就要十而分的小心:

1)如果其它對象的這個方法會消耗比較長的時間,那么就會導致鎖被我們持有了很長的時間;

2)如果其它對象的這個方法是一個同步方法,那么就要注意避免發生死鎖的可能性了;

最好是能夠避免在一個同步方法中調用其它對象的延時方法和同步方法。如果不能避免,就要采取上面說到的編碼技巧,打破死鎖的閉環,防止死鎖的發生。同時我們還可以盡量使用“不可變對象”來避免鎖的使用,在某些情況下還可以避免對象的共享,比如 new 一個新的對象代替共享的對象,因為鎖一般是對象上的,對象不相同了,也就可以避免死鎖,另外盡量避免使用靜態同步方法,因為靜態同步相當于全局鎖。還有一些封閉技術可以使用:比如堆棧封閉,線程封閉,threadlocal,這些技術可以減少對象的共享,也就減少了死鎖的可能性。

總結一下:

死鎖的根本原因

1)是多個線程涉及到多個鎖,這些鎖存在著交叉,所以可能會導致了一個鎖依賴的閉環;

2)默認的鎖申請操作是阻塞的。

所以要避免死鎖,就要在一遇到多個對象鎖交叉的情況,就要仔細審查這幾個對象的類中的所有方法,是否存在著導致鎖依賴的環路的可能性。要采取各種方法來杜絕這種可能性。

以上所述是小編給大家介紹的java中產生死鎖的原因及如何避免詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:https://blog.csdn.net/m0_38126177/article/details/78587845

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 被教官揉了一晚上的奶小说 | 精品国产在天天线在线麻豆 | 久久这里只有精品视频e | 久久热在线视频精品1 | 国产福利在线免费观看 | yjzz视频 | 龟甲情感超市全文阅读 小说 | 国产精品国语自产拍在线观看 | 成人免费播放 | 亚洲狠狠网站色噜噜 | 欧洲破处 | 国产玖玖在线观看 | 国产欧美精品一区二区三区四区 | 色视频国产 | 欧美一区二区三区大片 | 女同69式互添在线观看免费 | 国产香蕉久久 | 国产成人免费高清激情明星 | 1024国产基地永久免费 | 亚洲xxxxxhd奶水女人 | 日韩天堂视频 | 精品视频一区二区 | 激情视频图片小说qvdo | 亚洲欧美日韩另类在线一 | 国产福利一区二区在线精品 | 蛮荒的童话未删减在线观看 | 国产喂奶300部 | 日本大巴车强thepro | 国产亚洲人成网站天堂岛 | 喜欢老头吃我奶躁我的动图 | 久久精品国产免费播高清无卡 | 天美传媒在线视频 | jazz中国女人护士 | 国产精品久久毛片蜜月 | 24adc年龄18岁欢迎大驾光临 | 亚洲第一色网 | 2021国产精品成人免费视频 | 国产在线视频欧美亚综合 | 国产精品视频网 | a优女网| 国产高清自拍 |