#java线程死锁的检测方法
Java中线程状态:新建(New)、可运行(Runnable)、等待(Wating)、超时等待(Timed_Wating)、阻塞(Blocked)、Terminated(终止)。所有状态在Thread.state枚举类中。
状态转换图:
当线程中互相等待对方释放锁的时候就会都变成Blocked状态形成死锁,产生死锁的必要条件: **1. 互斥条件:**一个资源每次只能被一个进程使用。 **2. 请求与保持条件:**一个进程因请求资源而阻塞时,对已获得的资源保持不放。 **3. 不剥夺条件:**进程已获得的资源,在末使用完之前,不能强行剥夺。 **4. 循环等待条件:**若干进程之间形成一种头尾相接的循环等待资源关系。
例如: 测试threadA和threadB都进入无线等待,形成死锁。 代码如下:
public class ThreadTest {
private static final Object lockA = new Object();
private static final Object lockB = new Object();
public static void main(String[] args) throws Exception {
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockA) {
System.out.println("a thead run ...");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
synchronized (lockB) {
System.out.println("a thead end ...");
}
}
}
});
threadA.setName("threadA");
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockB) {
System.out.println("b thead run ...");
synchronized (lockA) {
System.out.println("b thead end ...");
}
}
}
});
threadB.setName("threadB");
threadA.start();
Thread.sleep(1000);
threadB.start();
}
}
当发生的死锁后,JDK自带了两个工具(jstack和JConsole),也可以使用VisualVm进行监控。
VisualVm
VisualVM会看到如下: 通过threadump可以看到更加详细的信息:
jstack
通过jstack展示线程堆栈信息(以Windows环境为例) 1.找到运行当前程序的JVM的进程id(测试使用的是eclipse运行,17572pid是eclipse) 2.执行jstack [pid] 这样就能清晰的查出是threadA
和threadB
线程互相等待产生死锁。推荐将线程命名,这样在线程堆栈dump中就能准确的定位是哪个线程,如果不进行命名将会由系统自动命名,不便于问题的查找。
工具是如何检测死锁的呢?
产生死锁也就意味着先生之间的等待关系出现了闭合环路,发生死锁。我们可以将等待关系想象成一个单项链表。那么也就将问题转化为判断这个链表中是否出现环路。如何检测单项链表中是否有闭合环路,请看我的另一片博客。