通过ThreadMXBean类来检查程序中的死锁

时间:2021-04-13 22:35:27

转载地址:http://www.importnew.com/15307.html

首先申明一下创建这个分类《技术分享》的原因,本人特别喜欢开源的代码,也非常热衷于别人分享喜欢的代码,看到一些精彩的技术贴总是自己手动尝试下,为了让更多的人能够看到这项技术以及防止以后自己遗忘,特别将自己手动实践后的代码,以及自己在写代码过程中的遇到的疑问记录下来,为开源世界尽自己的微博之力。


ThreadMXBean

Java虚拟机线程系统的管理接口。

Java 虚拟机具有此接口的实现类的单一实例。实现此接口的实例是一个 MXBean,可以通过调用 ManagementFactory.getThreadMXBean() 方法或从平台 MBeanServer 方法获得它。 
在 MBeanServer 内唯一标识线程系统的 MXBean 的 ObjectName 是: java.lang:type=Threading 

这个类只要用来管理线程信息。它其中包含连个方法findDeadlockedThreads()和findMonitorDeadlockedThreads(),用来查找处于死锁状态的线程。

二者的区别的是,findDeadlockedThreads还可以检测到owner locks(java.util.concurrent)引起的死锁,而findMonitorDeadlockedThreads只能检测monitor locks(例如,同步块)。findDeadlockedThreads是java5引入的,findMonitorDeadlockedThreads是java6引入的。

程序的思想是周期性的去检查有没有死锁发生。代码如下:

package org.zdnuist.demo.handlerdeadthread;

import java.lang.management.ThreadInfo;

public interface DeadlockHandler {

void handleDeadLock(final ThreadInfo[] deadLockThreads);

}
package org.zdnuist.demo.handlerdeadthread;import java.lang.management.ThreadInfo;public class DeadlockConsoleHandler implements DeadlockHandler{@Overridepublic void handleDeadLock(ThreadInfo[] deadLockThreads) {if(deadLockThreads != null){System.err.println("Deadlock detected!");//Map<Thread,StackTraceElement[]> stackTraceMap = Thread.getAllStackTraces();for(ThreadInfo threadInfo : deadLockThreads){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());} }}}}}}}
package org.zdnuist.demo.handlerdeadthread;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 schedule = Executors.newScheduledThreadPool(1);public DeadlockDetector(final DeadlockHandler deadlockHandler,final long period,final TimeUnit unit){this.deadlockHandler = deadlockHandler;this.period = period;this.unit = unit;}final Runnable deadlockCheck = new Runnable(){@Overridepublic void run() {long[] deadlockedThreads = DeadlockDetector.this.mBean.findDeadlockedThreads();if(deadlockedThreads != null){ThreadInfo[] threadInfos = DeadlockDetector.this.mBean.getThreadInfo(deadlockedThreads);DeadlockDetector.this.deadlockHandler.handleDeadLock(threadInfos);}}};public void start(){this.schedule.scheduleAtFixedRate(this.deadlockCheck, this.period, this.period, this.unit);}}
package org.zdnuist.demo.handlerdeadthread;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(){@Overridepublic void run() {synchronized (lock1) {System.out.println("Thread1 acquired lock1");try {TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized (lock2) {System.out.println("Thread1 acquired lock2");}}}};thread1.setName("Thread_1");thread1.start();Thread thread2 = new Thread(){public void run(){synchronized (lock2) {System.out.println("Thread2 acquired lock2");synchronized (lock1) {System.out.println("Thread2 acquired lock1");}}}};thread2.setName("Thread_2");thread2.start();}}


结束语:

死锁检测的开销可能会很大,你需要用你的程序来测试一下你是否真的需要死锁检测以及多久检测一次。我建议死锁检测的时间间隔至少为几分钟,因为更加频繁的检测并没有太大的意义,原因是我们并没有一个复原计划,我们能做的只是调试和处理错误或者重启程序并祈祷不会再次发生死锁。如果你有关于解决死锁问题的好建议或者关于这个解决方案的疑问,请在下面留言。