需要避免的与多任务处理有关的特殊错误类型是死锁(deadlock)。死锁发生在当两个线程对一对同步对象有循环依赖关系时。例如,假定一个线程进入了对象X的管程而另一个线程进入了对象Y的管程。如果X的线程试图调用Y的同步方法,它将像预料的一样被锁定。而Y的线程同样希望调用X的一些同步方法,线程永远等待,因为为到达X,必须释放自己的Y的锁定以使第一个线程可以完成。死锁是很难调试的错误,因为:
- 通常,它极少发生,只有到两线程的时间段刚好符合时才能发生。
- 它可能包含多于两个的线程和同步对象(也就是说,死锁在比刚讲述的例子有更多复杂的事件序列的时候可以发生)。
1 // An example of deadlock. 2 class A { 3 synchronized void foo(B b) { 4 String name = Thread.currentThread().getName(); 5 System.out.println(name + " entered A.foo"); 6 try { 7 Thread.sleep(1000); 8 } catch(Exception e) { 9 System.out.println("A Interrupted");10 }11 System.out.println(name + " trying to call B.last()");12 b.last();13 }14 synchronized void last() {15 System.out.println("Inside A.last");16 }17 }18 class B {19 synchronized void bar(A a) {20 String name = Thread.currentThread().getName();21 System.out.println(name + " entered B.bar");22 try {23 Thread.sleep(1000);24 } catch(Exception e) {25 System.out.println("B Interrupted");26 }27 System.out.println(name + " trying to call A.last()");28 a.last();29 }30 synchronized void last() {31 System.out.println("Inside A.last");32 }33 }34 class Deadlock implements Runnable {35 A a = new A();36 B b = new B();37 Deadlock() {38 Thread.currentThread().setName("MainThread");39 Thread t = new Thread(this, "RacingThread");40 t.start();41 a.foo(b); // get lock on a in this thread.42 System.out.println("Back in main thread");43 }44 public void run() {45 b.bar(a); // get lock on b in other thread.46 System.out.println("Back in other thread");47 }48 public static void main(String args[]) {49 new Deadlock();50 }51 }
运行程序后,输出如下:
MainThread entered A.foo
RacingThread entered B.barMainThread trying to call B.last()RacingThread trying to call A.last()因为程序死锁,你需要按CTRL-C来结束程序。在PC机上按CTRL-BREAK(或在Solaris下按CTRL-\)你可以看到全线程和管程缓冲堆。你会看到RacingThread在等待管程a时占用管程b,同时,MainThread占用a等待b。该程序永远都不会结束。像该例阐明的,你的多线程程序经常被锁定,死锁是你首先应检查的问题。 系列文章: