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线程互相等待,便发生死锁。
下一篇:
Java 中为什么禁止泛型数组