摘要:如果線程已經獲得鎖,還要獲得鎖,同時線程已經獲得鎖,還要獲得鎖,那么線程和就會一直阻塞住。
上文講到synchronized關鍵字在多線程中的使用,既然用到了鎖,就會有出現死鎖的情況。一個線程獲得鎖,如果其他線程也想獲得同樣的鎖就會阻塞住,等待鎖的釋放。如果線程A已經獲得鎖1,還要獲得鎖2,同時線程B已經獲得鎖2,還要獲得鎖1,那么線程A和B就會一直阻塞住。
例子依照慣例先舉個例子:
public class Test { public static void main(String[] args) throws InterruptedException { Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(new Test().new Tt1(lock1, lock2)); Thread t2 = new Thread(new Test().new Tt2(lock1, lock2)); t1.start(); t2.start(); } class Tt1 implements Runnable{ private Object lock1; private Object lock2; public Tt1(Object lock1,Object lock2) { this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { synchronized (lock1) { System.out.println(this.getClass()+"-------1"); try { Thread.sleep(1000); synchronized (lock2) { System.out.println(this.getClass()+"-------2"); } } catch (InterruptedException e) { e.printStackTrace(); } } } } class Tt2 implements Runnable{ private Object lock1; private Object lock2; public Tt2(Object lock1,Object lock2) { this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { synchronized (lock2) { System.out.println(this.getClass()+"-------1"); try { Thread.sleep(1000); synchronized (lock1) { System.out.println(this.getClass()+"-------2"); } } catch (InterruptedException e) { e.printStackTrace(); } } } } }
執行結果:
class Test$Tt1-------1 class Test$Tt2-------1
2個線程都只執行到了第一步,就沒有往下執行,都處于了阻塞狀態,這就是死鎖。
定位死鎖死鎖問題并不是一個容易被發現和定位的問題,如果系統出現死鎖問題,該如何定位?
1.使用jps,查詢java虛擬機的pid
2.使用jstack打印堆棧
以Thread-1為例介紹下每一部分的意思
1).Thread-1 線程名稱
2).prio=5 線程優先級
3).os_prio=0 本地的優先級
4).tid=0x000000001929b800 線程id
5).nid=0xfb34 本地的線程id
6)
java.lang.Thread.State: BLOCKED (on object monitor)
線程狀態處于阻塞
7) waiting to lock <0x00000000d5dd0c38> (a java.lang.Object)正在等待的鎖
8)locked <0x00000000d5dd0c48> (a java.lang.Object) 已獲取的鎖
現在我們可以看到Thread-1和Thread-0都處于阻塞狀態,Thread-1獲取了‘0x00000000d5dd0c48’鎖,等待‘0x00000000d5dd0c38’鎖,而Thread-0則剛好相反。
避免死鎖我們已經知道了死鎖的形成和定位,再來講講如何避免:
1.盡量在線程中不嵌套獲取多個資源,但你只需獲取一個時就不會出現死鎖、
2.如果不得不嵌套使用時,要多考慮嵌套的順序
3.死鎖是因為無限的阻塞等待,如果能有一個最大的等待時間就可以解決這個問題。synchronized不具備這個功能,但是我們可以使用Lock類中的tryLock方法去嘗試獲取鎖,這個方法可以指定一個超時時限,在等待超過該時限之后返回失敗信息
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76377.html
摘要:一個進程可以有多個線程。線程又叫做輕量級進程。這樣兩個進程相互無休止地等待下去,均無法繼續執行,此時兩個進程陷入死鎖狀態。不剝奪條件進程所獲得的資源在未使用完畢之前,不能被其他進程強行奪走,即只能由獲得該資源的進程自己來釋放只能是主動釋放。 歡迎進入JAVA基礎課程 博客地址:https://blog.csdn.net/houjiyu...本系列文章將主要針對JAVA一些基礎知識點進...
摘要:一個進程可以有多個線程。線程又叫做輕量級進程。這樣兩個進程相互無休止地等待下去,均無法繼續執行,此時兩個進程陷入死鎖狀態。不剝奪條件進程所獲得的資源在未使用完畢之前,不能被其他進程強行奪走,即只能由獲得該資源的進程自己來釋放只能是主動釋放。 歡迎進入JAVA基礎課程 博客地址:https://blog.csdn.net/houjiyu...本系列文章將主要針對JAVA一些基礎知識點進...
摘要:但是并不是什么多線程就可以隨便用,有的時候多線程反而會造成系統的負擔,而且多線程還會造成其他的數據問題,下面就來介紹一下多線程面臨的問題。下面這張圖是多線程運行時候的情況,我們發現上下文切換的次數暴增。 并發的概念: 在Java中是支持多線程的,多線程在有的時候可以大提高程序的速度,比如你的程序中有兩個完全不同的功能操作,你可以讓兩個不同的線程去各自執行這兩個操作,互不影響,不需要執行...
摘要:并發和并行并發和并行是兩個非常容易被混淆的概念。并發說的是在一個時間段內,多件事情在這個時間段內交替執行。并行說的是多件事情在同一個時刻同事發生。由于線程池是一個線程,得不到執行,而被餓死,最終導致了程序死鎖的現象。 同步(Synchronous)和異步(Asynchronous) 同步和異步通常來形容一次方法調用,同步方法調用一旦開始,調用者必須等到方法調用返回后,才能繼續后續的行為...
摘要:超詳細的面試題總結一之基本知識多線程和虛擬機創建線程有幾種不同的方式你喜歡哪一種為什么繼承類實現接口應用程序可以使用框架來創建線程池實現接口。死亡線程方法執行結束,或者因異常退出了方法,則該線程結束生命周期。死亡的線程不可再次復生。 超詳細的Java面試題總結(一)之Java基本知識 多線程和Java虛擬機 創建線程有幾種不同的方式?你喜歡哪一種?為什么? 繼承Thread類 實現R...
閱讀 2034·2021-11-11 16:54
閱讀 2111·2019-08-30 15:55
閱讀 3611·2019-08-30 15:54
閱讀 391·2019-08-30 15:44
閱讀 2228·2019-08-30 10:58
閱讀 424·2019-08-26 10:30
閱讀 3048·2019-08-23 14:46
閱讀 3191·2019-08-23 13:46