deadlock是两个或多个线程被永远阻塞。下例会导致deadlock的情况,我们看如何分析。
package com.fanshadoop.test;
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();
}
}
}
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.journaldev.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.journaldev.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.journaldev.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.journaldev.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.journaldev.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.journaldev.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.thread dump文件清晰表明了deadlock情况,thread和资源相互牵扯导致死锁的情况。
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.'); }
Lock Only what is required:仅在需要操作的对象上获取锁。
avoid waiting indefinitely:避免无限等待。如果两个线程使用thread join方式相互等待容易导致死锁。如果线程必须等待其他线程结束,最好使用你希望等待线程结束的最大时间。