Java多線程之死鎖詳解
1、死鎖
出現場景:當線程A擁有瞭A對象的鎖,想要去獲取B對象的鎖;線程B擁有瞭B對象的鎖,想要擁有A對象的鎖,兩個線程在獲取鎖的時候,都不會釋放已經持有的鎖,於是,就造成瞭死鎖。
示例代碼:
@Slf4j public class ThreadTest { private static Object objectA = new Object(); private static Object objectB = new Object(); public static void main(String[] args) throws InterruptedException { Thread t2 = new Thread(()->{ synchronized (objectA){ log.debug("線程t2獲取到瞭objectA"); synchronized (objectB){ log.debug("線程t2獲取到瞭objectB"); } } },"t2"); Thread t1 = new Thread(()->{ synchronized (objectB){ log.debug("線程t1獲取到瞭objectB"); synchronized (objectA){ log.debug("線程t1獲取到瞭objectA"); } } },"t1"); t2.start(); t1.start(); } }
如何檢測死鎖:
兩種方法
(1)找到本機jconsole程序,直接在windows系統搜索就可以,打開是這個樣子。
然後在本地進程裡面選擇你的進程,其實就是你的項目名稱。然後點擊連接,在點擊不安全連接。
進去之後點擊線程
再點擊檢測死鎖
最後就能看到死鎖的線程瞭
(2)首先是在idea的控制臺,打開Terminal,輸入【jps】命令查看所有的進程id,找到你自己的java類名稱對應的id。
然後輸入【jstack + 進程號】 就可以查詢到該進程的所有線程信息。在輸出信息的最下面,就可以看到如下圖所示的線程死鎖信息。
2、死鎖經典問題——哲學傢就餐問題
經典場景:有四位哲學及在一正方形的桌子上面吃飯,桌子的每個角有一根筷子,一共四根,那麼,當每個哲學傢都拿起自己左邊的筷子之後,再去拿自己右邊的筷子的時候,就會發現自己右邊沒有筷子,這時哲學就就會等右邊的哲學傢放下筷子,但是每個哲學傢都是這個想法,那麼都不會放下筷子,並且都拿不到右邊的筷子,因此就造成瞭死鎖。
代碼實現例子:
@Slf4j public class Thread1 { public static void main(String[] args) throws InterruptedException { //筷子對象 Chopsticks c1 = new Chopsticks("c1"); Chopsticks c2 = new Chopsticks("c2"); Chopsticks c3 = new Chopsticks("c3"); Chopsticks c4 = new Chopsticks("c4"); new Philosopher("李雲龍",c1,c2).start(); new Philosopher("趙剛",c2,c3).start(); new Philosopher("魏和尚",c3,c4).start(); new Philosopher("張大彪",c4,c1).start(); } } //筷子 class Chopsticks{ private String name; public Chopsticks(String name) { this.name = name; } } //哲學傢 @Slf4j class Philosopher extends Thread{ //名字 private String name; //筷子 private Chopsticks left; private Chopsticks right; public Philosopher(String name, Chopsticks left, Chopsticks right) { super(name); this.left = left; this.right = right; } @Override public void run() { while(true){ synchronized (right){ synchronized (left){ eat(name); } } } } private void eat(String name){ log.debug(name + "正在吃飯"); } }
測試結果:可以實現吃飯操作,但是會出現場景中描述的問題,出現線程死鎖。
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- Java如何正確的使用wait-notify方法你知道嗎
- Java多線程Thread類的使用及註意事項
- Java線程中的常見方法(start方法和run方法)
- 新手初學Java網絡編程
- Java幾個重要的關鍵字詳析