public class DeadLock { public static void main(final String[] args) throws Exception { final Object lock1 = new Object(); final Object lock2 = new Object(); Thread.currentThread().setName("main-thread"); final Thread r = new Thread("another-thread") { @Override public void run() { try { synchronized (lock2) { Thread.sleep(20000); synchronized (lock1) { Thread.sleep(20000); } } } catch (final Exception e) { e.printStackTrace(); } } }; r.start(); Thread.sleep(5000); synchronized (lock1) { Thread.sleep(20000); synchronized (lock2) { Thread.sleep(20000); } } } }
这段代码可能有点复杂,但原理不麻烦,就是描述了经典的加锁顺序问题。栈信息比较有趣,裁剪之后如下。
"another-thread" prio=6 tid=0x02b22400 nid=0x2250 waiting for monitor entry [0x0316f000] java.lang.Thread.State: BLOCKED (on object monitor) at DeadLock$1.run(DeadLock.java:14) - waiting to lock <0x22bc3f90> (a java.lang.Object) - locked <0x22bc3f98> (a java.lang.Object) Locked ownable synchronizers: - None "main-thread" prio=6 tid=0x00868800 nid=0x2634 waiting for monitor entry [0x0098f000] java.lang.Thread.State: BLOCKED (on object monitor) at DeadLock.main(DeadLock.java:28) - waiting to lock <0x22bc3f98> (a java.lang.Object) - locked <0x22bc3f90> (a java.lang.Object) Locked ownable synchronizers: - None Found one Java-level deadlock: ============================= "another-thread": waiting to lock monitor 0x02ad433c (object 0x22bc3f90, a java.lang.Object), which is held by "main-thread" "main-thread": waiting to lock monitor 0x02ad363c (object 0x22bc3f98, a java.lang.Object), which is held by "another-thread" Java stack information for the threads listed above: =================================================== "another-thread": at DeadLock$1.run(DeadLock.java:14) - waiting to lock <0x22bc3f90> (a java.lang.Object) - locked <0x22bc3f98> (a java.lang.Object) "main-thread": at DeadLock.main(DeadLock.java:28) - waiting to lock <0x22bc3f98> (a java.lang.Object) - locked <0x22bc3f90> (a java.lang.Object) Found 1 deadlock.
主线程中提示了当前持有的锁和期望获取的锁,而新线程也存在类似的提示,只是获取锁的顺序不同。从栈信息可以看出,两个线程都处于BLOCKED状态。可能是源代码中的问题过于明显,导出的栈信息中给出了死锁的提示信息,实际项目的业务代码比样例要复杂,JVM可能做不到这么智能。这里的提示信息多多少少有点让我失望,在主线程栈信息的最后一部分没有输出当前持有锁的列表,很奇怪,不知道是不是和JDK的实现有关。
import java.security.SecureRandom; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; public class DeadLock { private final ReentrantLock lock = new ReentrantLock(); private static final SecureRandom random = new SecureRandom(); public DeadLock() { } public void runWork() { final ThreadPoolExecutor threadpool = new ThreadPoolExecutor(3, 3, 60L, TimeUnit.DAYS, new SynchronousQueue<Runnable>(), new ThreadFactory() { private final AtomicInteger counter = new AtomicInteger(1); @Override public Thread newThread(final Runnable r) { return new Thread(r, "thread-sn-" + counter.getAndIncrement()); } }); threadpool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); Thread.currentThread().setName("main-thread"); for (int i = 0; i < 15; ++i) { threadpool.submit(new Runnable() { @Override public void run() { try { int timeout = 0; while ((timeout = random.nextInt()) <= 0) { } timeout = timeout % 111; Thread.sleep(timeout * 100L); lock.lock(); callLongTime(); } catch (final Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }); } threadpool.shutdown(); } public static void main(final String[] args) throws Exception { new DeadLock().runWork(); } static long callLongTime() { System.out.println("thread name " + Thread.currentThread().getName()); long sum = 0; for (long i = 0; i < 10000000000L; ++i) { sum = sum ^ i + i; } return sum; } }
最后一个样例,写的比较复杂,但事情比较简单,线程之间的同步关键字换成了Java5提供的concurrent库中的重入锁。
"thread-sn-3" prio=6 tid=0x02de8400 nid=0x2688 runnable [0x0320f000] java.lang.Thread.State: RUNNABLE at DeadLock.callLongTime(DeadLock.java:63) at DeadLock$2.run(DeadLock.java:41) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:722) Locked ownable synchronizers: - <0x22be1488> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) - <0x22be66d8> (a java.util.concurrent.ThreadPoolExecutor$Worker) "thread-sn-2" prio=6 tid=0x02de6c00 nid=0x218c waiting on condition [0x031bf000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x22be1488> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:867) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1197) at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:214) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290) at DeadLock$2.run(DeadLock.java:40) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:722) Locked ownable synchronizers: - <0x22be64e0> (a java.util.concurrent.ThreadPoolExecutor$Worker)
栈信息比较有趣,JVM在每个线程线的最后部分输出了当前线程持有的锁对象,类型和地址。从上述的信息中可以找到,当前处于运行状态的线程持有了一个地址为0x22be1488的锁,而这个锁正是其它线程等待获取的锁对象。
http://blog.csdn.net/jackie_xiaonan/article/details/8577785