造成死锁的原因
死锁是指两个或两个以上的线程在执行过程中,因争夺锁而造成的一种互相等待的现象,若无外力作用,它们都将一直等待下去。
造成死锁的示例
有两把锁,lock1、lock2
线程t1获取了锁lock1,等待锁lock2
线程t2获取了锁lock2,等待锁lock1
线程t1和t2相互等待对方已获取的锁,又不释放自己已获取的锁,导致两个线程相互等待,发生死锁。
public class DeadlockTest {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void lock() {
Thread t1 = new Thread(() -> {
try {
synchronized (lock1) {
System.out.println("t1:获取lock1成功");
Thread.sleep(2000);
synchronized (lock2) {
System.out.println("t1:获取lock2成功");
Thread.sleep(2000);
}
}
} catch (InterruptedException e) {
System.out.println("t1:中断");
}
});
Thread t2 = new Thread(() -> {
try {
synchronized (lock2) {
System.out.println("t2:获取lock2成功");
Thread.sleep(2000);
synchronized (lock1) {
System.out.println("t2:获取lock1成功");
Thread.sleep(2000);
}
}
} catch (InterruptedException e) {
System.out.println("t2:中断");
}
});
t1.start();
t2.start();
}
public static void main(String[] args) {
DeadlockTest deadlock = new DeadlockTest();
deadlock.lock();
}
}
如何避免死锁?
- 尽量不要用多个锁。
- 按照同一个顺序获取锁。
- 使用重入锁,通过重入锁的中断和限时等待规避死锁。
注意:死锁的线程不占用CPU。
定位死锁
- 使用
jps
命令找到JVM进程
- 然后使用
jstack -l PID
命令查看进程中的线程,查找是否有两个或者多个线程在相互获取对象持有的锁。
关于jstack命令的使用,可以参考 jvm jstack 命令
在jstack输出信息的最后面,有死锁相关的信息
使用在线分析工具FastThread,也能找到死锁相关的信息: