標籤:
需要避免的與多任務處理有關的特殊錯誤類型是死結(deadlock)。死結發生在當兩個線程對一對同步對象有循環相依性關係時。例如,假定一個線程進入了對象X的管程而另一個線程進入了對象Y的管程。如果X的線程試圖調用Y的同步方法,它將像預料的一樣被鎖定。而Y的線程同樣希望調用X的一些同步方法,線程永遠等待,因為為到達X,必須釋放自己的Y的鎖定以使第一個線程可以完成。死結是很難調試的錯誤,因為:
- 通常,它極少發生,只有到兩線程的時間段剛好符合時才能發生。
- 它可能包含多於兩個的線程和同步對象(也就是說,死結在比剛講述的例子有更多複雜的事件序列的時候可以發生)。
為充分理解死結,觀察它的行為是很有用的。下面的例子產生了兩個類,A和B,分別有foo( )和bar( )方法。這兩種方法在調用其他類的方法前有一個短暫的停頓。主類,名為Deadlock,建立了A和B的執行個體,然後啟動第二個線程去設定死結環境。foo( )和bar( )方法使用sleep( )強迫死結現象發生。
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.bar
MainThread trying to call B.last()
RacingThread trying to call A.last()
因為程式死結,你需要按CTRL-C來結束程式。在PC機上按CTRL-BREAK(或在Solaris下按CTRL-\)你可以看到全線程和管程緩衝堆。你會看到RacingThread在等待管程a時佔用管程b,同時,MainThread佔用a等待b。該程式永遠都不會結束。像該例闡明的,你的多線程程式經常被鎖定,死結是你首先應檢查的問題。
系列文章:
Java知多少(上)
Java知多少(39)interface介面
Java知多少(40)介面和抽象類別的區別
Java知多少(41)泛型詳解
Java知多少(42)泛型萬用字元和型別參數的範圍
Java知多少(43)異常處理基礎
Java知多少(44)異常類型
Java知多少(45)未被捕獲的異常
Java知多少(46)try和catch的使用
Java知多少(47)多重catch語句的使用
Java知多少(48)try語句的嵌套
Java知多少(49)throw:異常的拋出
Java知多少(50)Java throws子句
Java知多少(51)finally
Java知多少(52)內建異常
Java知多少(53)使用Java建立自己的異常子類
Java知多少(54)斷言詳解
Java知多少(55)線程
Java知多少(56)執行緒模式Java知多少(57)主線程Java知多少(58)線程Runnable介面和Thread類詳解Java知多少(59)建立多線程Java知多少(60)isAlive()和join()的使用Java知多少(61)線程優先順序Java知多少(62)線程同步Java知多少(63)線程間通訊
Java知多少(64)線程死結