【辰兮要努力】:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行!
博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端、后台、数据库、项目案例等相关知识点总结,感谢你的阅读和关注,希望我的博客能帮助到更多的人,分享获取新知,大家一起进步!
吾等采石之人,应怀大教堂之心,愿大家奔赴在各自的热爱里…
一、初识死锁
面试官:谈一下你对死锁的理解?
死锁就是两个或多个线程(或进程)被无限期地阻塞,相互等待对方手中资源的一种状态
一旦发生了死锁,根据发生死锁的线程的职责不同,就可能会造成 子系统崩溃、性能降低 甚至 整个系统崩溃 等各种不良后果。而且死锁往往发生在高并发、高负载的情况下,因为可能会直接影响到很多用户,造成一系列的问题
Java 死锁产生的四个必要条件:
1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路
打破死锁即打破如上四个中的一个满足条件即可
二、案例分析
面试官:请简单的写出一个具体的死锁案例!
如下两个对象在调度a资源的时候需要调度b资源,同时调度b资源的时候需要调度a资源,资源得不到释放,产生死锁
/**
* 2021-9-11 15:52:43
* 辰兮要努力
*/
public class TestDeadLock {
/*
* 所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进
*/
public static void main(String[] args) {
//创建两个资源 a资源和b资源互相调度
final Object a = new Object();
final Object b = new Object();
//线程A,按照先锁a再获得锁b的的顺序获得锁
new Thread() {
@Override
public void run(){
synchronized (a) {
System.out.println(Thread.currentThread().getName()+ "线程 已获取 a资源");
try {
//线程睡两秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "线程 想获取 b资源");
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "win");
}
}
}
}.start();
//线程B先获取锁b再锁a的顺序获得锁
new Thread() {
@Override
public void run(){
synchronized (b) {
System.out.println(Thread.currentThread().getName()+ "线程 已获取 b资源");
//线程睡两秒
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "线程 想获取 a资源");
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "win");
}
}
}
}.start();
}
}
执行效果如下
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去
三、排查解决
面试官:你如何排查项目中的死锁问题呢?
jps(Java Virtual Machine Process Status Tool)
jps是java提供的一个显示当前所有java进程pid的命令,适合在linux/unix平台上简单察看当前java进程的一些简单情况
输入的效果
C:\Users\lenovo>jps
10608 TestDeadLock
10848 Launcher
6640
18408 Jps
18460 KotlinCompileDaemon
jstack是java虚拟机自带的一种堆栈跟踪工具。
jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因
C:\Users\lenovo>jstack 10608
输入的效果
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x0000000003488e08 (object 0x000000076be21938, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x000000000348b698 (object 0x000000076be21948, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.chenxi.TestDeadLock$2.run(TestDeadLock.java:53)
- waiting to lock <0x000000076be21938> (a java.lang.Object)
- locked <0x000000076be21948> (a java.lang.Object)
"Thread-0":
at com.chenxi.TestDeadLock$1.run(TestDeadLock.java:33)
- waiting to lock <0x000000076be21948> (a java.lang.Object)
- locked <0x000000076be21938> (a java.lang.Object)
Found 1 deadlock.
如上的日志
"Thread-1":等待的去锁 <0x000000076be21938>
同时已经锁住了 <0x000000076be21948>
"Thread-0":等待的去锁 <0x000000076be21948>
同时已经锁住了<0x000000076be21938>
Found 1 deadlock.
同时日志里面有产生死锁的类和具体的行数
如上的方法我们可以准确的定位到死锁具体产生的位置,具体的业务场景就根据具体的情况分析解决
非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤️ 分享👥 留言💬thanks!!!
愿你们奔赴在自己的热爱里!