当前位置: 首页 > news >正文

一文详解Java中死锁产生原因、常见场景及排查解决思路(附详细案例代码)

01-死锁的概念

死锁是指两个或两个以上的线程在执行过程中,因抢夺资源而造成的一种互相等待的现象,若无外力干涉,则它们无法再继续推进下去

02-产生原因

  • 系统资源不足
  • 进程运行推进顺序不合适
  • 系统资源分配不当

03-常见死锁场景与示例

3.1嵌套锁顺序不一致

public class DeadLockDemo { static Object a = new Object(); static Object b = new Object(); public static void main(String[] args) { new Thread(() -> { synchronized (a){ System.out.println("t1线程持有a锁,试图获取b锁"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (b){ System.out.println("t1线程获取到b锁"); } } },"t1").start(); new Thread(() -> { synchronized (b){ System.out.println("t2线程持有a锁,试图获取a锁"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (a){ System.out.println("t2线程获取到a锁"); } } },"t2").start(); } }

分析:

  • t1线程执行:先获取a锁,再请求b锁
  • t2线程执行:先获取b锁,再请求a锁
  • 可能形成循环等待

3.2动态锁顺序死锁

public void transfer(Account from, Account to, int amount) { synchronized (from) { synchronized (to) { from.withdraw(amount); to.deposit(amount); } } }

分析:

如果两个线程同时调用transfer(),但参数顺序相反:

  • 线程A:transfer(account1, account2, 100)
  • 线程B:transfer(account2, account1, 200)

可能产生死锁

3.3资源死锁(如线程池任务相互等待)

ExecutorService executor = Executors.newFixedThreadPool(2); Future<?> future1 = executor.submit(() -> { Future<?> future2 = executor.submit(() -> System.out.println("Task2")); future2.get(); // 等待任务2完成 }); future1.get(); // 等待任务1完成

分析:

  • 线程池只有两个线程
  • 任务1提交任务2并等待任务2完成,任务2等待线程池空闲
  • 若任务2无法执行,任务1也无法完成,形成死锁

04-如何避免死锁

4.1 固定锁顺序

始终按全局一致顺序获取锁

public void transfer(Account a, Account b, int amount) { Object firstLock = a.id < b.id ? a : b; Object secondLock = a.id < b.id ? b : a; synchronized (firstLock) { synchronized (secondLock) { // 操作 } } }

4.2使用超时机制

tryLock()替代synchronized,设置超时时间

if (lock1.tryLock(100, TimeUnit.MILLISECONDS)) { try { if (lock2.tryLock(100, TimeUnit.MILLISECONDS)) { try { // 操作 } finally { lock2.unlock(); } } } finally { lock1.unlock(); } }

4.3 避免嵌套锁

尽量只持有一个锁,或 将多个锁封装为一个大锁

05-如何排查死锁

5.1 纯命令

  • jps -l—> 相当于 java ps -ef -l —>查看本地系统中所有正在运行的 Java 进程
  • jstack 进程编号—>查看进程堆栈信息

5.2 图形化

jconsole —>win + R 输入 jconsole,连接对应的Java进程,点击线程,点击检测死锁即可查看

http://www.jsqmd.com/news/94229/

相关文章:

  • 开放土壤光谱库:建立可复制的土壤校准模型(PLOS ONE,2025)
  • 在前端中list.map的用法
  • 【Dubbo从入门到精通:架构解析与实战落地】
  • Geo优化【双核四驱】驱动企业增长:权威专家于磊深度解析
  • 6G真的要来了?中国移动这次把“未来网络”摆到了台前
  • Yandex复杂还原验证码识别
  • sward全面介绍(11) - 如何有效保障文档的安全可靠
  • Google Vids:由AI驱动的工作视频创作 | ProductHunt 今日热榜 - 12月15日
  • 【专家亲授】低代码环境下PHP组件动态更新的8个最佳实践
  • Python中的直接赋值、浅拷贝与深拷贝:常见错误案例与深入理解
  • 基于Matlab/simulink的双电机建模驱动控制仿真模型:探索纯电与混动汽车世界
  • App项目后台如何用 XinServer 实现智能缓存机制?
  • 中海达“天空地水工”一体化监测体系,赋能安徽水利数字化变革
  • 黄金成色怎么看?新手第一次买金,别只盯着“亮不亮”
  • 自动驾驶—CARLA仿真(10)tutorial_gbuffer demo
  • 【技术教程】Qoder使用技巧分享
  • 半导体设备报警诊断程序技术方案
  • Transformer模型详解系列:Qwen-Image背后的MMDiT架构原理
  • 15000行C++代码,我实现了一个完整的JVM虚拟机(含GC和JIT)
  • Conda环境管理神器:Miniconda实现多版本Python自由切换
  • 揭秘大公开咯!提示工程架构师助力Agentic AI技术创新展翅高飞
  • 免费PPT模板大全!
  • 大家好,我是田螺.分享一道网上很火的腾讯面试题:40亿的QQ号,如何去重,1G的内存. 不过,有腾讯上班的朋友说,我们没出过这种面试题~ 哈哈~哈哈,anyway,这道题还是很有意思的. 它是一
  • AI一周资讯 251206-251212
  • 力扣--262. 行程和用户(数据库题目)
  • 泰雷兹推出AI Security Fabric,为Agentic AI和LLM驱动的应用提供运行时安全防护
  • Notepad官网下载后,搭配Seed-Coder-8B-Base实现智能编程?
  • 自主算力筑基 垂域模型破局:国产硬件架构下的行业大模型训练与微调服务实践
  • Qwen3-VL-8B与Codex对比:谁更适合中文多模态任务?
  • 目标检测数据集 第080期-基于yolo标注格式的电线杆基础连接件分割数据集(含免费分享)