java死锁

文章目录

  • 1、概念
  • 2、解决和预防策略:
    • [1. 按固定顺序获取锁(破坏"循环等待")](#1. 按固定顺序获取锁(破坏“循环等待”))
    • [2. 使用超时机制(破坏"占有并等待")](#2. 使用超时机制(破坏“占有并等待”))
    • [3. 一次性申请所有资源(破坏"占有并等待")](#3. 一次性申请所有资源(破坏“占有并等待”))
  • [3、 死锁检测与恢复](#3、 死锁检测与恢复)

1、概念

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:

复制代码
互斥条件:一个资源每次只能被一个进程使用。

请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

由于"互斥"是锁的基本特性,我们无法破坏它。因此解决方案主要集中在破坏后三个条件。

2、解决和预防策略:

1. 按固定顺序获取锁(破坏"循环等待")

这是最常用、最有效的预防手段。强制所有线程以相同的顺序申请锁。

场景:

比如转账操作,线程 A 从账户 1 转给账户 2,线程 B 从账户 2 转给账户 1。如果一个先锁 1 再锁 2,另一个先锁 2 再锁 1,就容易死锁。

解决:规定一个全局顺序,比如永远先锁 ID 小的账户,再锁 ID 大的账户。

2. 使用超时机制(破坏"占有并等待")

不要让线程无限期地等待锁。如果在指定时间内拿不到锁,就放弃当前操作或稍后重试。

使用 ReentrantLock.tryLock():

java 复制代码
1Lock lock1 = new ReentrantLock();
2Lock lock2 = new ReentrantLock();
3
4// 尝试获取锁,最多等待 1 秒
5if (lock1.tryLock(1, TimeUnit.SECONDS)) {
6    try {
7        if (lock2.tryLock(1, TimeUnit.SECONDS)) {
8            try {
9                // 执行业务逻辑
10            } finally {
11                lock2.unlock();
12            }
13        }
14    } finally {
15        lock1.unlock();
16    }
17}
18// 如果没拿到锁,可以记录日志、重试或返回失败,而不是死锁

使用 synchronized 的替代方案:synchronized 无法设置超时,一旦拿不到锁就会一直阻塞,所以高并发场景建议优先使用 ReentrantLock。

3. 一次性申请所有资源(破坏"占有并等待")

如果一个线程需要多个资源,要么全部申请到,要么一个都不申请。

实现:可以通过一个全局的"资源管理器"来统一分配资源,或者使用 tryLock 尝试获取所有需要的锁,如果有一个获取失败,就释放已获取的锁并重试。

缺点:实现起来比较复杂,可能会降低吞吐量。

3、 死锁检测与恢复

使用 JDK 工具:

  • jstack:在命令行输入 jstack ,如果检测到死锁,JVM
    会直接在控制台输出死锁信息,告诉你哪两个线程在互相等待哪个锁。
  • jconsole / --jvisualvm:图形化界面工具,连接到 Java
    进程后,点击"检测死锁"按钮,能直观地看到死锁的线程和堆栈。
策略 破坏的条件 推荐程度 说明
统一锁顺序 循环等待 ⭐⭐⭐⭐⭐ 最常用,通过排序强制顺序
超时获取锁 占有并等待 ⭐⭐⭐⭐ 使用 ReentrantLock.tryLock()
死锁检测 - ⭐⭐⭐ 发生后及时发现,利用 jstackThreadMXBean
一次性申请 占有并等待 ⭐⭐ 实现复杂,性能可能不高
相关推荐
陳10302 小时前
C++:多态
开发语言·c++
LiLiYuan.2 小时前
在资源管理器打开IDEA未进行版本管理的文件的方法
java·ide·intellij-idea
XXOOXRT2 小时前
基于SpringBoot-验证码
java·spring boot·后端
lvbinemail2 小时前
配置jenkins.service
java·运维·jenkins·systemctl
ss2732 小时前
若依分离版后端集成 Camunda 7 工作流引擎
java·若依
明天…ling2 小时前
sql注入(1-10关)
java·数据库·sql
m0_497214152 小时前
qt实现打印机功能
开发语言·qt
Ashley_Amanda2 小时前
SAP调用Web Service全流程详解
java·前端·数据库
笨手笨脚の2 小时前
Linux JDK NIO 源码分析
java·linux·nio