简单的说:线程1持有A锁,线程2持有B锁;线程1尝试获取B锁,线程2尝试获取A锁。两个线程各持有了一把锁,同时想获取对方的锁,自身的又不释放。
死锁
先写一个死锁的程序
public class DeadLock extends Thread {
private String first;
private String second;
public DeadLock(String first, String second) {
this.first = first;
this.second = second;
}
public void run() {
synchronized (first) {
System.out.println(this.getName() + ":" + first);
try {
Thread.sleep(2000);
synchronized (second) {
System.out.println(this.getName() + ":" + second);
}
} catch (InterruptedException e) {
}
}
}
public static void main(String[] args) throws InterruptedException {
String lockA = "锁A";
String lockB = "锁B";
DeadLock thread1 = new DeadLock(lockA, lockB);
DeadLock thread2 = new DeadLock(lockB, lockA);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
执行结果:
Thread-0:锁A
Thread-1:锁B
几乎每次都会出现死锁的情况,如果项目中遇到这种问题如何排查:
1. 使用jdk原生工具jstack
使用jps或者ps确定进程ID,然后执行 jstack PID
image.png
可以清楚看到Thread1 和Thread0 互相等待对方锁。
2.使用MXBean工具
修改示例中的main方法,使用MXBean的findDeadLockedThreads方法
public static void main(String[] args) throws InterruptedException {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
Runnable runnable = new Runnable() {
@Override
public void run() {
long[] allThreadIds = threadMXBean.findDeadlockedThreads();
if (allThreadIds != null){
ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(allThreadIds);
System.out.println("deadLock threads:");
for (ThreadInfo t :threadInfo) {
System.out.println(t.getThreadName());
}
}
}
};
ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1);
//等待10s,每10s检查一次
scheduled.scheduleAtFixedRate(runnable,10,10, TimeUnit.SECONDS);
String lockA = "锁A";
String lockB = "锁B";
DeadLock thread1 = new DeadLock(lockA, lockB);
DeadLock thread2 = new DeadLock(lockB, lockA);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
执行结果
Thread-0:锁A
Thread-1:锁B
deadLock threads:
Thread-1
Thread-0
deadLock threads:
Thread-1
Thread-0
当程序发生死锁不仅排查起来耗时,而且只能重启,修改程序本身代码来弥补。所以当写程序的时候如何避免死锁显得重要的多。
从代码程序上
工具上
其他方式
自旋锁发生死锁如何排查,程序中经常遇到的OOM 排查方式一样。
top查看下CPU使用最高的进程,然后打出堆栈信息排查代码。
内存泄漏排查: