通过编程发现Java死锁
通过stack也可以发现死锁。
测试类
import java.util.concurrent.TimeUnit; public class Test { public static void main(String[] args) { DeadlockDetector deadlockDetector = new DeadlockDetector(new DeadlockConsoleHandler(), 5, TimeUnit.SECONDS); deadlockDetector.start(); final Object lock1 = new Object(); final Object lock2 = new Object(); Thread thread1 = new Thread(()->{ synchronized (lock1) { System.out.println("Thread1 acquired lock1"); try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException ignore) { } synchronized (lock2) { System.out.println("Thread1 acquired lock2"); } } }); thread1.start(); Thread thread2 = new Thread(()->{ synchronized (lock2) { System.out.println("Thread2 acquired lock2"); synchronized (lock1) { System.out.println("Thread2 acquired lock1"); } } }); thread2.start(); } }
处理类
public class DeadlockConsoleHandler implements DeadlockHandler { @Override public void handleDeadlock(final ThreadInfo[] deadlockedThreads) { if (deadlockedThreads != null) { System.err.println("Deadlock detected!"); Map<Thread, StackTraceElement[]> stackTraceMap = Thread.getAllStackTraces(); for (ThreadInfo threadInfo : deadlockedThreads) { if (threadInfo != null) { for (Thread thread : Thread.getAllStackTraces().keySet()) { if (thread.getId() == threadInfo.getThreadId()) { System.err.println(threadInfo.toString().trim()); for (StackTraceElement ste : thread.getStackTrace()) { System.err.println("t" + ste.toString().trim()); } } } } } } } } import java.lang.management.ThreadInfo; public interface DeadlockHandler { void handleDeadlock(final ThreadInfo[] deadlockedThreads); }
关键类
import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class DeadlockDetector { private final DeadlockHandler deadlockHandler; private final long period; private final TimeUnit unit; private final ThreadMXBean mbean = ManagementFactory.getThreadMXBean(); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); final Runnable deadlockCheck = new Runnable() { @Override public void run() { long[] deadlockedThreadIds = mbean.findDeadlockedThreads(); if (deadlockedThreadIds != null) { ThreadInfo[] threadInfos = mbean.getThreadInfo(deadlockedThreadIds); deadlockHandler.handleDeadlock(threadInfos); } } }; public DeadlockDetector(final DeadlockHandler deadlockHandler, final long period, final TimeUnit unit) { this.deadlockHandler = deadlockHandler; this.period = period; this.unit = unit; } public void start() { this.scheduler.scheduleAtFixedRate(this.deadlockCheck, this.period, this.period, this.unit); } }
测试结果
Thread1 acquired lock1 Thread2 acquired lock2 Deadlock detected! "Thread-1" Id=12 BLOCKED on java.lang.Object@6a80bb83 owned by "Thread-0" Id=11 ttest.Test.lambda$main$1(Test.java:32) ttest.Test$$Lambda$2/363771819.run(Unknown Source) tjava.lang.Thread.run(Thread.java:745) "Thread-0" Id=11 BLOCKED on java.lang.Object@6ebf220b owned by "Thread-1" Id=12 ttest.Test.lambda$main$0(Test.java:23) ttest.Test$$Lambda$1/668386784.run(Unknown Source) tjava.lang.Thread.run(Thread.java:745) Deadlock detected!