您好,登錄后才能下訂單哦!
死鎖是兩個(gè)甚至多個(gè)線程被永久阻塞時(shí)的一種運(yùn)行局面,這種局面的生成伴隨著至少兩個(gè)線程和兩個(gè)或者多個(gè)資源。在這里我已寫好一個(gè)簡(jiǎn)單的程序,它將會(huì)引起死鎖方案然后我們就會(huì)明白如何分析它。
Java死鎖范例
ThreadDeadlock.java
package com.bjpowernode.threads; public class ThreadDeadlock { public static void main(String[] args) throws InterruptedException { Object obj1 = new Object(); Object obj2 = new Object(); Object obj3 = new Object(); Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1"); Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2"); Thread t3 = new Thread(new SyncThread(obj3, obj1), "t3"); t1.start(); Thread.sleep(5000); t2.start(); Thread.sleep(5000); t3.start(); } } class SyncThread implements Runnable{ private Object obj1; private Object obj2; public SyncThread(Object o1, Object o2){ this.obj1=o1; this.obj2=o2; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " acquiring lock on "+obj1); synchronized (obj1) { System.out.println(name + " acquired lock on "+obj1); work(); System.out.println(name + " acquiring lock on "+obj2); synchronized (obj2) { System.out.println(name + " acquired lock on "+obj2); work(); } System.out.println(name + " released lock on "+obj2); } System.out.println(name + " released lock on "+obj1); System.out.println(name + " finished execution."); } private void work() { try { Thread.sleep(30000); } catch (InterruptedException e) { e.printStackTrace(); } } }
在上面的程序中同步線程正完成Runnable的接口,它工作的是兩個(gè)對(duì)象,這兩個(gè)對(duì)象向?qū)Ψ綄で笏梨i而且都在使用同步阻塞。
在主函數(shù)中,我使用了三個(gè)為同步線程運(yùn)行的線程,而且在其中每個(gè)線程中都有一個(gè)可共享的資源。
這些線程以向第一個(gè)對(duì)象獲取封鎖這種方式運(yùn)行。但是當(dāng)它試著像第二個(gè)對(duì)象獲取封鎖時(shí),它就會(huì)進(jìn)入等待狀態(tài),因?yàn)樗呀?jīng)被另一個(gè)線程封鎖住了。這樣,在線程引起死鎖的過(guò)程中,就形成了一個(gè)依賴于資源的循環(huán)。
當(dāng)我執(zhí)行上面的程序時(shí),就產(chǎn)生了輸出,但是程序卻因?yàn)樗梨i無(wú)法停止。
t1 acquiring lock on java.lang.Object@6d9dd520
t1 acquired lock on java.lang.Object@6d9dd520
t2 acquiring lock on java.lang.Object@22aed3a5
t2 acquired lock on java.lang.Object@22aed3a5
t3 acquiring lock on java.lang.Object@218c2661
t3 acquired lock on java.lang.Object@218c2661
t1 acquiring lock on java.lang.Object@22aed3a5
t2 acquiring lock on java.lang.Object@218c2661
t3 acquiring lock on java.lang.Object@6d9dd520
在此我們可以清楚地在輸出結(jié)果中辨認(rèn)出死鎖局面,但是在我們實(shí)際生活所用的應(yīng)用中,發(fā)現(xiàn)死鎖并將它排除是非常難的。
分析死鎖
2012-12-27 19:08:34 Full thread dump Java HotSpot(TM) 64-Bit Server VM (23.5-b02 mixed mode): "Attach Listener" daemon prio=5 tid=0x00007fb0a2814000 nid=0x4007 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "DestroyJavaVM" prio=5 tid=0x00007fb0a2801000 nid=0x1703 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "t3" prio=5 tid=0x00007fb0a204b000 nid=0x4d07 waiting for monitor entry [0x000000015d971000] java.lang.Thread.State: BLOCKED (on object monitor) at com.bjpowernode.threads.SyncThread.run(ThreadDeadlock.java:41) - waiting to lock <0x000000013df2f658> (a java.lang.Object) - locked <0x000000013df2f678> (a java.lang.Object) at java.lang.Thread.run(Thread.java:722) "t2" prio=5 tid=0x00007fb0a1073000 nid=0x4207 waiting for monitor entry [0x000000015d209000] java.lang.Thread.State: BLOCKED (on object monitor) at com.bjpowernode.threads.SyncThread.run(ThreadDeadlock.java:41) - waiting to lock <0x000000013df2f678> (a java.lang.Object) - locked <0x000000013df2f668> (a java.lang.Object) at java.lang.Thread.run(Thread.java:722) "t1" prio=5 tid=0x00007fb0a1072000 nid=0x5503 waiting for monitor entry [0x000000015d86e000] java.lang.Thread.State: BLOCKED (on object monitor) at com.bjpowernode.threads.SyncThread.run(ThreadDeadlock.java:41) - waiting to lock <0x000000013df2f668> (a java.lang.Object) - locked <0x000000013df2f658> (a java.lang.Object) at java.lang.Thread.run(Thread.java:722) "Service Thread" daemon prio=5 tid=0x00007fb0a1038000 nid=0x5303 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread1" daemon prio=5 tid=0x00007fb0a1037000 nid=0x5203 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" daemon prio=5 tid=0x00007fb0a1016000 nid=0x5103 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" daemon prio=5 tid=0x00007fb0a4003000 nid=0x5003 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" daemon prio=5 tid=0x00007fb0a4800000 nid=0x3f03 in Object.wait() [0x000000015d0c0000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x000000013de75798> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) - locked <0x000000013de75798> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177) "Reference Handler" daemon prio=5 tid=0x00007fb0a4002000 nid=0x3e03 in Object.wait() [0x000000015cfbd000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x000000013de75320> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:503) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133) - locked <0x000000013de75320> (a java.lang.ref.Reference$Lock) "VM Thread" prio=5 tid=0x00007fb0a2049800 nid=0x3d03 runnable "GC task thread#0 (ParallelGC)" prio=5 tid=0x00007fb0a300d800 nid=0x3503 runnable "GC task thread#1 (ParallelGC)" prio=5 tid=0x00007fb0a2001800 nid=0x3603 runnable "GC task thread#2 (ParallelGC)" prio=5 tid=0x00007fb0a2003800 nid=0x3703 runnable "GC task thread#3 (ParallelGC)" prio=5 tid=0x00007fb0a2004000 nid=0x3803 runnable "GC task thread#4 (ParallelGC)" prio=5 tid=0x00007fb0a2005000 nid=0x3903 runnable "GC task thread#5 (ParallelGC)" prio=5 tid=0x00007fb0a2005800 nid=0x3a03 runnable "GC task thread#6 (ParallelGC)" prio=5 tid=0x00007fb0a2006000 nid=0x3b03 runnable "GC task thread#7 (ParallelGC)" prio=5 tid=0x00007fb0a2006800 nid=0x3c03 runnable "VM Periodic Task Thread" prio=5 tid=0x00007fb0a1015000 nid=0x5403 waiting on condition JNI global references: 114 Found one Java-level deadlock: ============================= "t3": waiting to lock monitor 0x00007fb0a1074b08 (object 0x000000013df2f658, a java.lang.Object), which is held by "t1" "t1": waiting to lock monitor 0x00007fb0a1010f08 (object 0x000000013df2f668, a java.lang.Object), which is held by "t2" "t2": waiting to lock monitor 0x00007fb0a1012360 (object 0x000000013df2f678, a java.lang.Object), which is held by "t3" Java stack information for the threads listed above: =================================================== "t3": at com.bjpowernode.threads.SyncThread.run(ThreadDeadlock.java:41) - waiting to lock <0x000000013df2f658> (a java.lang.Object) - locked <0x000000013df2f678> (a java.lang.Object) at java.lang.Thread.run(Thread.java:722) "t1": at com.bjpowernode.threads.SyncThread.run(ThreadDeadlock.java:41) - waiting to lock <0x000000013df2f668> (a java.lang.Object) - locked <0x000000013df2f658> (a java.lang.Object) at java.lang.Thread.run(Thread.java:722) "t2": at com.bjpowernode.threads.SyncThread.run(ThreadDeadlock.java:41) - waiting to lock <0x000000013df2f678> (a java.lang.Object) - locked <0x000000013df2f668> (a java.lang.Object) at java.lang.Thread.run(Thread.java:722) Found 1 deadlock.
這三個(gè)線程轉(zhuǎn)存的輸出清楚地說(shuō)明了死鎖環(huán)境和線程,以及包含死鎖環(huán)境的資源。
為了分析死鎖,我們需要關(guān)注死鎖狀態(tài)的線程,然后資源再等待去封鎖,每一個(gè)資源都有一個(gè)獨(dú)特的ID,有了這個(gè)ID我們就能發(fā)現(xiàn)是哪一個(gè)進(jìn)程已經(jīng)封鎖住對(duì)象。舉個(gè)例子,線程“t3”正在等待封鎖0x000000013df2f658,但是它已經(jīng)被線程“t1”封鎖住了。
當(dāng)我們分析死鎖環(huán)境的時(shí)候,如果發(fā)現(xiàn)線程正在引起死鎖,這是我們就要改變代碼來(lái)避免死鎖的產(chǎn)生。
避免死鎖
有很多方針可供我們使用來(lái)避免死鎖的局面。
避免嵌套封鎖:這是死鎖最主要的原因的,如果你已經(jīng)有一個(gè)資源了就要避免封鎖另一個(gè)資源。如果你運(yùn)行時(shí)只有一個(gè)對(duì)象封鎖,那是幾乎不可能出現(xiàn)一個(gè)死鎖局面的。例如,這里是另一個(gè)運(yùn)行中沒有嵌套封鎖的run()方法,而且程序運(yùn)行沒有死鎖局面,運(yùn)行得很成功。
public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " acquiring lock on " + obj1); synchronized (obj1) { System.out.println(name + " acquired lock on " + obj1); work(); } System.out.println(name + " released lock on " + obj1); System.out.println(name + " acquiring lock on " + obj2); synchronized (obj2) { System.out.println(name + " acquired lock on " + obj2); work(); } System.out.println(name + " released lock on " + obj2); System.out.println(name + " finished execution."); }
只對(duì)有請(qǐng)求的進(jìn)行封鎖:你應(yīng)當(dāng)只想你要運(yùn)行的資源獲取封鎖,比如在上述程序中我在封鎖的完全的對(duì)象資源。但是如果我們只對(duì)它所屬領(lǐng)域中的一個(gè)感興趣,那我們應(yīng)當(dāng)封鎖住那個(gè)特殊的領(lǐng)域而并非完全的對(duì)象。
避免無(wú)限期的等待:如果兩個(gè)線程正在等待對(duì)象結(jié)束,無(wú)限期的使用線程加入,如果你的線程必須要等待另一個(gè)線程的結(jié)束,若是等待進(jìn)程的結(jié)束加入最好準(zhǔn)備最長(zhǎng)時(shí)間。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。