死锁,什么是死锁,怎么发现死锁
什么是死锁
死锁是发生在并发编程之中,多个线程在获取锁的过程之中发生阻塞,导致没有线程可以继续执行的情况。
例如线程t1先锁住了A对象,与此同时线程t2又锁住了B对象,而t1线程需要继续获取B对象的锁,t2线程需要继续获取A对象的锁,那么这个时候就会导致线程t1和t2同时发生阻塞,造成了死锁的现象。
@Slf4j
public class DeadLock {
public static final Object A = new Object();
public static final Object B = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (A){
log.info("锁住了A");
synchronized (B) {
log.info("锁住了B");
}
}
},"t1").start();
new Thread(() -> {
synchronized (B){
log.info("锁住了B");
synchronized (A) {
log.info("锁住了A");
}
}
},"t2").start();
}
}
运行代码之后就发生了阻塞:
我们并不知道发生死锁的代码在哪里,那么我们怎么定位发生死锁的线程和代码位置呢?
发现死锁
这里使用IDEA进行演示。 打开IDEA之中的终端
使用jps和jstack
首先使用
jps命令得到进程ID。找到与类名对应的进程ID
使用
jstack命令加 进程ID 得到进程里运行的线程信息。
可以得到下面的信息
Found one Java-level deadlock:
=============================
"t1":
waiting to lock monitor 0x00000183b3096b50 (object 0x0000000713dd89c0, a java.lang.Object),
which is held by "t2"
"t2":
waiting to lock monitor 0x00000183b3095030 (object 0x0000000713dd89b0, a java.lang.Object),
at com.example.juc.DeadLock$$Lambda$28/0x000000080100f3d0.run(Unknown Source)
at java.lang.Thread.run(java.base@17.0.7/Thread.java:833)
"t2":
at com.example.juc.DeadLock.lambda$main$1(DeadLock.java:28)
- waiting to lock <0x0000000713dd89b0> (a java.lang.Object)
- locked <0x0000000713dd89c0> (a java.lang.Object)
at com.example.juc.DeadLock$$Lambda$29/0x000000080100f5e8.run(Unknown Source)
at java.lang.Thread.run(java.base@17.0.7/Thread.java:833)
Found 1 deadlock.
从信息之中,JVM帮我们发现了一个死锁,并指出了发生死锁的线程信息和发生死锁的代码位置。此时我们就定位到了发生死锁的位置。
使用jconsole的方式
JVM同样还为我们提供了图形化的方式来查看进程中线程的信息。同样在终端输入jconsole
选择对应的进程进入。 选择线程->检测死锁
此时jconsole就非常方便的帮我们得到了发生死锁的线程的信息。