Java中因join呼叫引發的兩種死鎖情形
阿新 • • 發佈:2019-02-02
最近做的一個專案使用Java編寫,在除錯中遇到兩種因為呼叫join()引發的死鎖情形,很隱蔽。記錄於此。
1.執行緒join自身發生死鎖
1.執行緒join自身發生死鎖
public class Starter { public static void main(String[] args) { new DeadThread().start(); } } class DeadThread { public DeadThread() { thread = new Thread(new RealThread()); } public void start() { thread.start(); } private Thread thread; private class RealThread implements Runnable{ public void run() { System.out.println("Thread is starting..."); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread is stopping..."); } } }
執行緒RealThread呼叫thread.join()本是想與另一個執行緒同步(示例程式碼中沒有展示),但正如示例程式碼表現的那樣,thread實際指向了它自身,這就形成了一種詭異的死鎖情形:一個正在執行中的執行緒呼叫join()來等待自己結束。
2.鎖的維護不當
相比上面的情形,下面的情景則更為常見。
上面的程式碼在大部分情況下都能正常工作,但是死鎖的情形依然存在。執行緒以如下的順序執行時,就出現了死鎖:import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Starter { public static void main(String[] args) { DeadThread dt = new DeadThread(); dt.start(); dt.stop(); } } class DeadThread { public DeadThread() { thread = new Thread(new RealThread()); lock = new ReentrantLock(); } public void start() { thread.start(); } public void stop() { lock.lock(); try { // do some real works... running = false; thread.join(); // (2) } catch(Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } private Thread thread; private Lock lock; private volatile boolean running = true; private class RealThread implements Runnable{ public void run() { while (running) { // (1) lock.lock(); // (3) try { // do some real works... System.out.println("Thread is running..."); } finally { lock.unlock(); } } } } }
<1>RealThread執行緒執行到(1)處,即while(running)執行完時,被DeadThread執行緒搶佔
<2>DeadThread執行緒呼叫stop()函式,而此時的thread指向<1>中的RealThread執行緒,當stop()函式執行到(2)處,會等待RealThread的結束,放棄CPU
<3>RealThread執行緒恢復執行,此時因為DeadThread佔有lock鎖,所以RealThread會在(3)處等待執行緒DeadThread釋放lock
在<3>執行完後,DeadThread執行緒和RealThread執行緒互相等待,便發生死鎖。