在Java中编程死锁检测

如何以编程方式检测Java程序中是否发生了死锁?

您可以使用JDK附带的ThreadMXBean以编程方式执行此操作:

 ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long[] threadIds = bean.findDeadlockedThreads(); // Returns null if no threads are deadlocked. if (threadIds != null) { ThreadInfo[] infos = bean.getThreadInfo(threadIds); for (ThreadInfo info : infos) { StackTraceElement[] stack = info.getStackTrace(); // Log or store stack trace information. } } 

显然你应该尝试隔离哪个线程执行这个死锁检查 – 否则,如果该线程死锁,将无法运行检查!

顺便说一下,这是JConsole正在使用的内容。

一个有用的暗示调查:

如果你能抓住应用程序并怀疑发生了死锁,那么请在java.exe控制台窗口(或Solaris / Linux上的“Ctrl- \”)上按“Ctrl-Break”键。 jvm将转储所有线程的当前状态和堆栈跟踪,找出死锁并精确描述它们。

它看起来像这样:

 Full thread dump Java HotSpot(TM) Client VM (1.5.0_09-b03 mixed mode): "[Test Timer] Request Queue" prio=6 tid=0x13d708d0 nid=0x1ec in Object. wait() [0x1b00f000..0x1b00fb68] at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Unknown Source) at library.util.AsyncQueue.run(AsyncQueue.java:138) - locked <0x02e70000> (a test.server.scheduler.SchedulerRequestQueue) ... Found one Java-level deadlock: ============================= "Corba service": waiting to lock monitor 0x13c06684 (object 0x04697d90, a java.lang.Object), which is held by "[Server Connection] Heartbeat Timer" "[Server Connection] Heartbeat Timer": waiting to lock monitor 0x13c065c4 (object 0x0467e728, a test.proxy.ServerProxy), which is held by "Corba service" Java stack information for the threads listed above: =================================================== "Corba service": at test.proxy.ServerProxy.stopHBWatchDog(ServerProxy:695) - waiting to lock <0x04697d90> (a java.lang.Object) ... 

JArmus是一个死锁检测和避免库。 它包括对Thread.joinCyclicBarrierCountDownLatchPhaserReentrantLock

要使用JArmus,您需要testing您的代码。 无论是通过其中一个仪器类,或自动与JARmus instrumentar jarmusc

java -jar jarmusc.jar yourprogram.jar checkedprogram.jar

inputyourprogram.jar是你想检查的程序。 输出是相同的程序与检查自动发现任何死锁。

障碍需要一些帮助

使用类CyclicBarrierCountDownLatchPhaser检查死锁有点棘手 – 例如,JConsole无法检测到这些types的死锁。 JArmus需要你的一点帮助:你必须指定哪些线程正在影响同步,我们称之为已注册的线程。

线程必须尽快标记为已注册。 标记已注册线程的好地方在Runnable.run的开始处。 JArmus.register(latch);

以下程序,僵局是由JArmus正确识别的:

 final CountDownLatch latch = new CountDownLatch(2); final CyclicBarrier barrier = new CyclicBarrier(2); final Queue<Exception> exceptions = new ArrayDeque<>(); Thread t1 = new Thread(new Runnable() { @Override public void run() { try { JArmus.register(barrier); // do not forget to register! JArmus.register(latch); // do not forget to register! latch.countDown(); latch.await(); barrier.await(); } catch (Exception e) { exceptions.add(e); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { JArmus.register(barrier); // do not forget to register! JArmus.register(latch); // do not forget to register! barrier.await(); latch.countDown(); latch.await(); } catch (Exception e) { exceptions.add(e); } } }); t1.start(); t2.start(); 

您可能要考虑IBM的MTRAT 。 毕竟,预防胜于治疗。 多核软件开发套件还附带一个死锁检测工具。

如果您不需要编程检测,则可以通过JConsole进行此操作; 在线程选项卡上有一个“检测死锁”button。 在JDK6中,它检测内部监视器和juc Lock

通过$JAVA_HOM/bin/jconsole命令运行JConsole

您可以使用ThreadMXBean类以编程方式检测死锁的线程。这里是代码,

  ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long ids[] = bean.findMonitorDeadlockedThreads(); if(ids != null) { ThreadInfo threadInfo[] = bean.getThreadInfo(ids); for (ThreadInfo threadInfo1 : threadInfo) { System.out.println(threadInfo1.getThreadId()); //Prints the ID of deadlocked thread System.out.println(threadInfo1.getThreadName()); //Prints the name of deadlocked thread System.out.println(threadInfo1.getLockName()); //Prints the string representation of an object for which thread has entered into deadlock. System.out.println(threadInfo1.getLockOwnerId()); //Prints the ID of thread which currently owns the object lock System.out.println(threadInfo1.getLockOwnerName()); //Prints name of the thread which currently owns the object lock. } } else { System.out.println("No Deadlocked Threads"); } 

点击这里获取更多关于如何检测死锁线程的信息。

这里有代码: http : //www.java2s.com/Code/Java/Development-Class/在应用程序中使用javalangpipe理API程序地执行程序删除检测API.htm

ThreadMonitor.findDeadlock()发生了这个ThreadMonitor.findDeadlock()

  public boolean findDeadlock() { long[] tids; if (findDeadlocksMethodName.equals("findDeadlockedThreads") && tmbean.isSynchronizerUsageSupported()) { tids = tmbean.findDeadlockedThreads(); if (tids == null) { return false; } System.out.println("Deadlock found :-"); ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true); for (ThreadInfo ti : infos) { printThreadInfo(ti); printLockInfo(ti.getLockedSynchronizers()); System.out.println(); } } else { tids = tmbean.findMonitorDeadlockedThreads(); if (tids == null) { return false; } ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE); for (ThreadInfo ti : infos) { // print thread information printThreadInfo(ti); } } return true; } 

这将调用Java 5和6中具有不同名称的ThreadMXBean的API(因此,外部的if() )。

代码示例还允许中断locking,因此您甚至可以打破死锁。

tempus-fugit也实现了它与一个程序化的线程转储类。 它使用上面提到的mbean机制来实现,并提供了一个开箱即用的超级解决scheme。

如果你想在运行时完成,你可以使用看门狗 。