Java死鎖_動力節(jié)點(diǎn)Java學(xué)院整理
死鎖是兩個(gè)甚至多個(gè)線程被永久阻塞時(shí)的一種運(yùn)行局面,這種局面的生成伴隨著至少兩個(gè)線程和兩個(gè)或者多個(gè)資源。在這里我已寫好一個(gè)簡單的程序,它將會引起死鎖方案然后我們就會明白如何分析它。
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è)對象,這兩個(gè)對象向?qū)Ψ綄で笏梨i而且都在使用同步阻塞。
在主函數(shù)中,我使用了三個(gè)為同步線程運(yùn)行的線程,而且在其中每個(gè)線程中都有一個(gè)可共享的資源。
這些線程以向第一個(gè)對象獲取封鎖這種方式運(yùn)行。但是當(dāng)它試著像第二個(gè)對象獲取封鎖時(shí),它就會進(jìn)入等待狀態(tài),因?yàn)樗呀?jīng)被另一個(gè)線程封鎖住了。這樣,在線程引起死鎖的過程中,就形成了一個(gè)依賴于資源的循環(huán)。
當(dāng)我執(zhí)行上面的程序時(shí),就產(chǎn)生了輸出,但是程序卻因?yàn)樗梨i無法停止。
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)存的輸出清楚地說明了死鎖環(huán)境和線程,以及包含死鎖環(huán)境的資源。
為了分析死鎖,我們需要關(guān)注死鎖狀態(tài)的線程,然后資源再等待去封鎖,每一個(gè)資源都有一個(gè)獨(dú)特的ID,有了這個(gè)ID我們就能發(fā)現(xiàn)是哪一個(gè)進(jìn)程已經(jīng)封鎖住對象。舉個(gè)例子,線程“t3”正在等待封鎖0x000000013df2f658,但是它已經(jīng)被線程“t1”封鎖住了。
當(dāng)我們分析死鎖環(huán)境的時(shí)候,如果發(fā)現(xiàn)線程正在引起死鎖,這是我們就要改變代碼來避免死鎖的產(chǎn)生。
避免死鎖
有很多方針可供我們使用來避免死鎖的局面。
避免嵌套封鎖:這是死鎖最主要的原因的,如果你已經(jīng)有一個(gè)資源了就要避免封鎖另一個(gè)資源。如果你運(yùn)行時(shí)只有一個(gè)對象封鎖,那是幾乎不可能出現(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."); }
只對有請求的進(jìn)行封鎖:你應(yīng)當(dāng)只想你要運(yùn)行的資源獲取封鎖,比如在上述程序中我在封鎖的完全的對象資源。但是如果我們只對它所屬領(lǐng)域中的一個(gè)感興趣,那我們應(yīng)當(dāng)封鎖住那個(gè)特殊的領(lǐng)域而并非完全的對象。
避免無限期的等待:如果兩個(gè)線程正在等待對象結(jié)束,無限期的使用線程加入,如果你的線程必須要等待另一個(gè)線程的結(jié)束,若是等待進(jìn)程的結(jié)束加入最好準(zhǔn)備最長時(shí)間。
相關(guān)文章
java中List集合及其實(shí)現(xiàn)類的方法詳解
本篇文章給大家?guī)淼膬?nèi)容是關(guān)于java中List集合及其實(shí)現(xiàn)類的方法介紹(附代碼),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對你有所幫助。下面我們就來學(xué)習(xí)一下吧2019-06-06Java框架Quartz中API、Jobs和Trigger詳解
這篇文章主要介紹了Java框架Quartz中API、Jobs和Trigger詳解,JobDetail?對象是在將?job?加入?scheduler?時(shí),由客戶端程序(你的程序)創(chuàng)建的,它包含?job?的各種屬性設(shè)置,以及用于存儲?job?實(shí)例狀態(tài)信息的?JobDataMap,需要的朋友可以參考下2023-11-11Spring Boot 2.0快速構(gòu)建服務(wù)組件全步驟
這篇文章主要給大家介紹了關(guān)于Spring Boot 2.0快速構(gòu)建服務(wù)組件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Spring Boot 2.0具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04最有價(jià)值的50道java面試題 適用于準(zhǔn)入職Java程序員
這篇文章主要為大家分享了最有價(jià)值的50道java面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,對hashCode方法的設(shè)計(jì)、垃圾收集的堆和代進(jìn)行剖析,感興趣的小伙伴們可以參考一下2016-05-05