1. 程式人生 > >Java中因join呼叫引發的兩種死鎖情形

Java中因join呼叫引發的兩種死鎖情形

最近做的一個專案使用Java編寫,在除錯中遇到兩種因為呼叫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執行緒互相等待,便發生死鎖。