线程死锁会导致线程阻塞,若有大量线程阻塞,将会导致线程资源被耗尽,最终会导到系统崩溃,无法对外服务。
发现线程死锁,需要依赖监控系统。监控系统可以定时使用jstack 命令采集线程信息,jstack命令中可以查看到死锁的详细信息,进行告警或者人工介入干预等。
代码示例:
public class DeadlockTest {
// 创建两个共享资源
private static final String resource1 = new String();
private static final Object resource2 = new Object();
public static void main(String[] args) {
/**
* 两个线程 thread1 thread2
* thread1对resource1上锁,然后尝试获取resource2的锁;
* thread2对resource2上锁,然后尝试获取resource1的锁;
* 2个线程会相互等待,出现死锁
*/
Thread thread1 = new Thread(() -> {
synchronized (resource1) {
System.out.println("Thread 1: 锁定resource1");
try {
Thread.sleep(100); // 假设这里有其他操作,需要一些时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1: 尝试索取resource2的锁");
//尝试索取resource2的锁
synchronized (resource2) {
System.out.println("Thread 1: 锁定 resource2");
}
}
}, "thread1");
Thread thread2 = new Thread(() -> {
synchronized (resource2) {
System.out.println("Thread 2: 锁定 resource2");
try {
Thread.sleep(100); // 假设这里有其他操作,需要一些时间
} catch (InterruptedException e) {
e.printStackTrace();
}
//尝试索取resource1的锁
System.out.println("Thread 2: 尝试索取resource1的锁");
synchronized (resource1) {
System.out.println("Thread 2: 锁定 resource1");
}
}
}, "thread2");
// 启动线程
thread1.start();
thread2.start();
}
}
定位死锁代码
1、方法一:jps+jstack
jps:jdk自带工具,可以查看所有的java进程

示例代码进程id是2504。
jstack:查看命令死锁信息,jdk自带的工具,可以查看某个java进程中所有的线程快照,可以看到死锁的相关信息。使用方式:jstack 进程id
执行jstack 2504,从输出结果中得到thread1和thread2死锁的代码位置:

2、方式二:jvisualvm
jvisualvm工具:jdk自带的工具。在cmd中运行jvisualvm,就可以打开这个工具。

使用方式:


3、方式三:arthas
阿里开源的工具,特别好用的一个jvm线上问题诊断工具。
详情见:
https://arthas.aliyun.com/doc/quick-start.html
下载解压:

在cmd运行: java -jar arthas-boot.jar

如图,输入4:

输入thread -b,得到thread1的id是22,thread2的id是23:


死锁常见的解决方案
- 避免使用多个锁:通过合理设计程序,尽量避免多个线程同时争用一样的资源
- 保持锁的有序性:当使用多个锁时,保持所有线程获取锁的顺序一致,以避免因顺序不一致导致的死锁。
- 超时等待:设置锁的超时时间,当等待超过必定时间后,放弃对锁的请求,进行其他的处理。
- 死锁检测和恢复:使用工具来检测和恢复死锁,一旦检测到死锁,可以通过中断线程、释放资源等方式来恢复程序的执行。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END



















暂无评论内容