Java線程優先級
需要避免的與多任務處理有關的特殊錯誤類型是死鎖(deadlock)。死鎖發生在當兩個線程對一對同步對象有循環依賴關系時。例如,假定一個線程進入了對象X的管程而另一個線程進入了對象Y的管程。如果X的線程試圖調用Y的同步方法,它將像預料的一樣被鎖定。而Y的線程同樣希望調用X的一些同步方法,線程永遠等待,因為為到達X,必須釋放自己的Y的鎖定以使第一個線程可以完成。死鎖是很難調試的錯誤,因為:
通常,它極少發生,只有到兩線程的時間段剛好符合時才能發生。
它可能包含多于兩個的線程和同步對象(也就是說,死鎖在比剛講述的例子有更多復雜的事件序列的時候可以發生)。
為充分理解死鎖,觀察它的行為是很有用的。下面的例子生成了兩個類,A和B,分別有foo( )和bar( )方法。這兩種方法在調用其他類的方法前有一個短暫的停頓。主類,名為Deadlock,創建了A和B的實例,然后啟動第二個線程去設置死鎖環境。foo( )和bar( )方法使用sleep( )強迫死鎖現象發生。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
// An example of deadlock. class A { synchronized void foo(B b) { String name = Thread.currentThread().getName(); System.out.println(name + " entered A.foo" ); try { Thread.sleep( 1000 ); } catch (Exception e) { System.out.println( "A Interrupted" ); } System.out.println(name + " trying to call B.last()" ); b.last(); } synchronized void last() { System.out.println( "Inside A.last" ); } } class B { synchronized void bar(A a) { String name = Thread.currentThread().getName(); System.out.println(name + " entered B.bar" ); try { Thread.sleep( 1000 ); } catch (Exception e) { System.out.println( "B Interrupted" ); } System.out.println(name + " trying to call A.last()" ); a.last(); } synchronized void last() { System.out.println( "Inside A.last" ); } } class Deadlock implements Runnable { A a = new A(); B b = new B(); Deadlock() { Thread.currentThread().setName( "MainThread" ); Thread t = new Thread( this , "RacingThread" ); t.start(); a.foo(b); // get lock on a in this thread. System.out.println( "Back in main thread" ); } public void run() { b.bar(a); // get lock on b in other thread. System.out.println( "Back in other thread" ); } public static void main(String args[]) { new Deadlock(); } } |
運行程序后,輸出如下:
1
2
3
4
|
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線程死鎖
需要避免的與多任務處理有關的特殊錯誤類型是死鎖(deadlock)。死鎖發生在當兩個線程對一對同步對象有循環依賴關系時。例如,假定一個線程進入了對象X的管程而另一個線程進入了對象Y的管程。如果X的線程試圖調用Y的同步方法,它將像預料的一樣被鎖定。而Y的線程同樣希望調用X的一些同步方法,線程永遠等待,因為為到達X,必須釋放自己的Y的鎖定以使第一個線程可以完成。死鎖是很難調試的錯誤,因為:
通常,它極少發生,只有到兩線程的時間段剛好符合時才能發生。
它可能包含多于兩個的線程和同步對象(也就是說,死鎖在比剛講述的例子有更多復雜的事件序列的時候可以發生)。
為充分理解死鎖,觀察它的行為是很有用的。下面的例子生成了兩個類,A和B,分別有foo( )和bar( )方法。這兩種方法在調用其他類的方法前有一個短暫的停頓。主類,名為Deadlock,創建了A和B的實例,然后啟動第二個線程去設置死鎖環境。foo( )和bar( )方法使用sleep( )強迫死鎖現象發生。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
// An example of deadlock. class A { synchronized void foo(B b) { String name = Thread.currentThread().getName(); System.out.println(name + " entered A.foo" ); try { Thread.sleep( 1000 ); } catch (Exception e) { System.out.println( "A Interrupted" ); } System.out.println(name + " trying to call B.last()" ); b.last(); } synchronized void last() { System.out.println( "Inside A.last" ); } } class B { synchronized void bar(A a) { String name = Thread.currentThread().getName(); System.out.println(name + " entered B.bar" ); try { Thread.sleep( 1000 ); } catch (Exception e) { System.out.println( "B Interrupted" ); } System.out.println(name + " trying to call A.last()" ); a.last(); } synchronized void last() { System.out.println( "Inside A.last" ); } } class Deadlock implements Runnable { A a = new A(); B b = new B(); Deadlock() { Thread.currentThread().setName( "MainThread" ); Thread t = new Thread( this , "RacingThread" ); t.start(); a.foo(b); // get lock on a in this thread. System.out.println( "Back in main thread" ); } public void run() { b.bar(a); // get lock on b in other thread. System.out.println( "Back in other thread" ); } public static void main(String args[]) { new Deadlock(); } } |
運行程序后,輸出如下:
1
2
3
4
|
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。該程序永遠都不會結束。像該例闡明的,你的多線程程序經常被鎖定,死鎖是你首先應檢查的問題。