聊聊死锁
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。
文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。
死锁的四个必要条件
- 互斥:一个资源不能同时被多个进程共享
- 请求与保持:一个进程若已经获得了部分资源,还在请求另一个资源时,不会释放已请求到的资源
- 不可剥夺:不能剥夺进程未使用完的资源,只能自己使用完后释放
- 循环等待:多个进程互相循环等待对方的资源
![image]()
如何避免死锁
四个条件逐一破坏
- 破坏“互斥”:资源的互斥一般是不可以被破坏的,虽有主要破坏其他三个条件
- 破坏“请求与保持”:进程必须一次性申请万所有资源才能运行
- 破坏“不可剥夺”:进程拥有未使用完资源,又同时申请其他资源而失败时,必须释放这些未使用完的资源,待到下次要使用时再重新申请
- 破坏“循环等待”:给所有资源编号,进程申请资源时必须按序申请
如何检测死锁
先运行一段死锁程序:
public class ThreadTest {
public static void main(String[] args) {
testLockedThread(); //模拟并检测死锁
}
public static void testLockedThread(){
//第一个线程
new Thread(()->{
synchronized(Integer.class){
try {
Thread.sleep(1000);
System.out.println("线程1开始获取String锁...");
synchronized (String.class){
System.out.println("线程1获取String锁成功!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//第二个线程
new Thread(new Runnable() {
@Override
public void run() {
synchronized(String.class){
try {
Thread.sleep(1000);
System.out.println("线程2获取Integer锁...");
synchronized (Integer.class){
System.out.println("线程2获取Integer锁成功!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:

- 使用JConsole工具
在JAVA_HOME/bin目录下有一个虚拟机监控工具JConsole,双击运行后选择一个想要监控的进程,这里选择刚刚启动的发生死锁的进程:
![image]()
进入后选择“线程”->“检测死锁”,就可以查看刚刚发生死锁的这个线程信息
Thread-0:
Thread-1:

可知,在线程Thread-0中,它申请java.lang.Class@6d6f6e28这个资源,但这个资源已被Thread-1占用;同理,在线程Thread-1中,它申请java.lang.Class@72ea2f77这个资源,当这个资源已被Thread-0占用,故发生了死锁
- 使用jdk自带的命令行工具Jstack
- 使用jdk1.8的接口ThreadMXBean
乐观锁的实现原理
版本号机制+递归
如果数据库中的确发生了死锁,应该怎么解决
分多种情况:
- 事务间对资源交替访问:
如用户A锁住了表A又去访问表B,同时用户B锁住了表B又去访问表A,就造成了A、B互相等待对方的锁而发生死锁 ;只能通过检查程序代码解决 - 并发修改同一条记录:如A拿到了独占锁正准备修改一条记录->同时B进来拿到共享锁读该条记录,读完后正准备修改该条记录->A想修改这条记录就必须让B先释放共享锁(A等B),B想修改就必须让A释放独占锁(B等A),这样就造成了死循环;解决方法:使用乐观锁(版本号机制+递归)、悲观锁(每次都加锁)
- 索引失效引发死锁
索引也是一种资源,当多个事务对资源进行争夺、互相等待时就会引发死锁
OK,如果文章哪里有错误或不足,欢迎各位留言。
创作不易,各位的「三连」是二少创作的最大动力!我们下期见!



浙公网安备 33010602011771号