死锁分析
发生死锁需要满足4个条件:
1. 互斥条件:一个资源每次只能被一个进程使用。
2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
下面代码模拟了死锁:
package me.zyc.lock.test;
public class DeadLock{
public static void methodA(){
String thread_name = Thread.currentThread().getName();
System.out.println(thread_name + " acquiring lock on LockA.class");
synchronized (LockA.class) {
System.out.println(thread_name + " locked on LockA.class");
doSomething(); // wait other thread lock on LockB
System.out.println(thread_name + " acquiring lock on LockB.class");
synchronized (LockB.class) {
System.out.println(thread_name + "locked on LockB.class");
if(true) for(;;){}
}
System.out.println(thread_name + " released lock on LockB.class");
}
System.out.println(thread_name + " released lock on LockA.class");
}
public static void methodB(){
String thread_name = Thread.currentThread().getName();
System.out.println(thread_name + " acquiring lock on LockB.class");
synchronized (LockB.class) {
System.out.println(thread_name + " locked on LockB.class");
doSomething(); // wait other thread lock on LockA
System.out.println(thread_name + " acquiring lock on LockA.class");
synchronized (LockA.class) {
System.out.println(thread_name + " locked on LockA.class");
if(true) for(;;){}
}
System.out.println(thread_name + " released lock on LockA.class");
}
System.out.println(thread_name + " released lock on LockB.class");
}
public static void doSomething(){
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
DeadLock.methodA();
}
}).start();
new Thread(new Runnable() {
public void run() {
DeadLock.methodB();
}
}).start();
}
private class LockA{}
private class LockB{}
}
代码运行输出如下:
- thread-0 获取了锁LockA,thread-1 获取了锁LockB。
- thread-0 尝试获取LockB,但是由于thread-1一直占用LockB未释放,thread-0被阻塞。
- thread-1尝试获取LockA,但是由于thread-0一直占用LockA未释放,thread-1被阻塞
jstack是Java自带线程分析工具,用法如下:
执行jstack -l pid,结果如下:
- thread-0 和 thread-1均处于BLOCKED状态。
- thread-0 获取了锁LockA,并等待获取LockB。
- thread-1 获取了锁LockB,并等待获取LockjA。
在最后jstack给出了更详细的死锁信息