Java死锁_动力节点Java学院整理
死锁是两个甚至多个线程被永久阻塞时的一种运行局面,这种局面的生成伴随着至少两个线程和两个或者多个资源。在这里我已写好一个简单的程序,它将会引起死锁方案然后我们就会明白如何分析它。
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的接口,它工作的是两个对象,这两个对象向对方寻求死锁而且都在使用同步阻塞。
在主函数中,我使用了三个为同步线程运行的线程,而且在其中每个线程中都有一个可共享的资源。
这些线程以向第一个对象获取*这种方式运行。但是当它试着像第二个对象获取*时,它就会进入等待状态,因为它已经被另一个线程*住了。这样,在线程引起死锁的过程中,就形成了一个依赖于资源的循环。
当我执行上面的程序时,就产生了输出,但是程序却因为死锁无法停止。
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
在此我们可以清楚地在输出结果中辨认出死锁局面,但是在我们实际生活所用的应用中,发现死锁并将它排除是非常难的。
分析死锁
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.
这三个线程转存的输出清楚地说明了死锁环境和线程,以及包含死锁环境的资源。
为了分析死锁,我们需要关注死锁状态的线程,然后资源再等待去*,每一个资源都有一个独特的id,有了这个id我们就能发现是哪一个进程已经*住对象。举个例子,线程“t3”正在等待*0x000000013df2f658,但是它已经被线程“t1”*住了。
当我们分析死锁环境的时候,如果发现线程正在引起死锁,这是我们就要改变代码来避免死锁的产生。
避免死锁
有很多方针可供我们使用来避免死锁的局面。
避免嵌套*:这是死锁最主要的原因的,如果你已经有一个资源了就要避免*另一个资源。如果你运行时只有一个对象*,那是几乎不可能出现一个死锁局面的。例如,这里是另一个运行中没有嵌套*的run()方法,而且程序运行没有死锁局面,运行得很成功。
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."); }
只对有请求的进行*:你应当只想你要运行的资源获取*,比如在上述程序中我在*的完全的对象资源。但是如果我们只对它所属领域中的一个感兴趣,那我们应当*住那个特殊的领域而并非完全的对象。
避免无限期的等待:如果两个线程正在等待对象结束,无限期的使用线程加入,如果你的线程必须要等待另一个线程的结束,若是等待进程的结束加入最好准备最长时间。
推荐阅读
-
Java守护线程实例详解_动力节点Java学院整理
-
Java死锁_动力节点Java学院整理
-
Java异常详解_动力节点Java学院整理
-
Java concurrency线程池之线程池原理(一)_动力节点Java学院整理
-
Java concurrency线程池之线程池原理(二)_动力节点Java学院整理
-
Java concurrency集合之CopyOnWriteArraySet_动力节点Java学院整理
-
Java concurrency集合之LinkedBlockingDeque_动力节点Java学院整理
-
Java concurrency之Condition条件_动力节点Java学院整理
-
Java concurrency之CountDownLatch原理和示例_动力节点Java学院整理
-
Filter、Servlet、Listener的学习_动力节点Java学院整理