Java 核心技术面试精讲
杨晓峰
前 Oracle 首席工程师
125942 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 44 讲
Java 核心技术面试精讲
15
15
1.0x
00:00/00:00
登录|注册

第18讲 | 什么情况下Java程序会产生死锁?如何定位、修复?

思考题:如何诊断某个线程进入死循环导致其他线程一直等待的问题
类加载过程中的死锁
静态代码分析
使用带超时的方法
设计好锁的获取顺序
避免使用多个锁
并发相关元素
线程状态
jstack工具
循环依赖关系
长期持有的互斥条件
互斥条件
一课一练
其他死锁场景
预防死锁
定位死锁
死锁产生原因
参考文章

该思维导图由 AI 生成,仅供参考

今天,我会介绍一些日常开发中类似线程死锁等问题的排查经验,并选择一两个我自己修复过或者诊断过的核心类库死锁问题作为例子,希望不仅能在面试时,包括在日常工作中也能对你有所帮助。
今天我要问你的问题是,什么情况下 Java 程序会产生死锁?如何定位、修复?

典型回答

死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此一直处于等待之中,没有任何个体可以继续前进。死锁不仅仅是在线程之间会发生,存在资源独占的进程之间同样也可能出现死锁。通常来说,我们大多是聚焦在多线程场景中的死锁,指两个或多个线程之间,由于互相持有对方需要的锁,而永久处于阻塞的状态。
你可以利用下面的示例图理解基本的死锁问题:
定位死锁最常见的方式就是利用 jstack 等工具获取线程栈,然后定位互相之间的依赖关系,进而找到死锁。如果是比较明显的死锁,往往 jstack 等就能直接定位,类似 JConsole 甚至可以在图形界面进行有限的死锁检测。
如果程序运行时发生了死锁,绝大多数情况下都是无法在线解决的,只能重启、修正程序本身问题。所以,代码开发阶段互相审查,或者利用工具进行预防性排查,往往也是很重要的。

考点分析

今天的问题偏向于实用场景,大部分死锁本身并不难定位,掌握基本思路和工具使用,理解线程相关的基本概念,比如各种线程状态和同步、锁、Latch 等并发工具,就已经足够解决大多数问题了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Java程序产生死锁的情况及解决方法 本文深入探讨了Java程序中死锁的产生原因以及解决方法。死锁是多线程环境下的一种特殊状态,由于线程相互持有对方需要的锁而陷入永久阻塞。文章介绍了如何通过工具如jstack来定位死锁,并提出了在程序开发阶段进行互相审查和利用工具进行预防性排查的重要性。此外,还介绍了如何使用Java提供的标准管理API来扫描服务进程、定位死锁,并提出了预防死锁的方法,包括避免使用多个锁、设计好锁的获取顺序、使用带超时的方法以及通过静态代码分析等。最后,文章还提到了一些更为复杂的死锁情况,并给出了相应的解决方法。总的来说,掌握线程相关的基本概念和工具使用对于解决大多数死锁问题已经足够重要,对于开发人员来说,这些知识和技能可以帮助他们更好地排查和解决类似线程死锁等问题。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 核心技术面试精讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(32)

  • 最新
  • 精选
  • 石头狮子
    1. 死锁的另一个好朋友就是饥饿。死锁和饥饿都是线程活跃性问题。 实践中死锁可以使用 jvm 自带的工具进行排查。 2. 课后题提出的死循环死锁可以认为是自旋锁死锁的一种,其他线程因为等待不到具体的信号提示。导致线程一直饥饿。 这种情况下可以查看线程 cpu 使用情况,排查出使用 cpu 时间片最高的线程,再打出该线程的堆栈信息,排查代码。 3. 基于互斥量的锁如果发生死锁往往 cpu 使用率较低,实践中也可以从这一方面进行排查。

    作者回复: 很好的总结

    2018-06-16
    177
  • I am a psycho
    当是死循环引起的其他线程阻塞,会导致cpu飙升,可以先看下cpu的使用率。

    作者回复: 对,比如Linux上,可以使用top命令配合grep Java之类,找到忙的pid;然后,转换成16进制,就是jstack输出中的格式;再定位代码

    2018-06-16
    2
    64
  • curlev3
    回答老师的问题 可以通过linux下top命令查看cpu使用率较高的java进程,进而用top -Hp ➕pid查看该java进程下cpu使用率较高的线程。再用jstack命令查看线程具体调用情况,排查问题。

    作者回复: 非常不错

    2018-06-26
    3
    54
  • 西鄉十六夜
    老师,面试遇到过一个很刁钻的问题。如何在jvm不重启的情况下杀死一个线程,在stop被移除后,如果线程存在死锁那是否意味着必须要修复代码再重启虚拟机呢?

    作者回复: 不知道有什么好办法,也许用我例子哪个API去找到死锁线程,想办法把死锁条件打开;但我觉得这东西不靠谱,假设真的解除死锁,你还能保证程序正确性吗,这不会是个通用解决方案 另外,即使以前有stop方法,blocked状态的线程也是关不了的吧,它不响应你的请求的

    2018-07-10
    32
  • 残阳
    以前做排查的时候看thread dump, 一般都会直接按一些关键字搜索。比如wait,lock之类,然后再找重复的内存地址。看完这遍文章之后感觉对死锁的理解更深刻。

    作者回复: 谢谢,地址也很重要

    2018-06-17
    12
  • 陈一嘉
    任务线程规范命名,详细记录逻辑运行日志。jstack查看线程状态。

    作者回复: 不错

    2018-06-16
    10
  • 肖一林
    初学nio的时候确实动不动就发生死锁。现在好像也没有特别好的教程,都是一些java.io的教程。很多教程跟不上技术的迭代。也可能是因为直接io编程在项目实践中偏少。 另外,这个小程序的图片不能放大看,不知道是微信的原因还是小程序的原因。老师看到了帮忙反馈一下。

    作者回复: nio确实教程少,书籍也不好找 Java IO,NIO,NIO2好像也没引进;如果想系统学习,我建议买本 《netty实战》,Java自己的nio定位偏重于基础性API,与终端应用需求有点鸿沟

    2018-06-16
    7
  • jacy
    尽然可以用ThreadMXBean来抓线程死锁信息,受教了。 循环死锁,会导致cpu某线程的cpu时间片占用率相当高,可以结合操作系统工具分析出线程号,然后用jstack分析线程

    作者回复: 不错

    2018-06-22
    5
  • 肖一林
    一课一练: 最典型的场景是nio的Selector类,这个类内部有三个集合,并且对这些集合做了同步。如果多个线程同时操作一个Selector,就很容易发生死锁。它的select方法会一直拿着锁,并且循环等待事件发生。如果有其他线程在修改它内部的集合数据,就死锁了。 同样用jstack可以发现问题,找出被阻塞的线程,看它等待哪个锁,再找到持有这把锁的线程,这个线程一搬处于运行状态

    作者回复: 不错,selected key 和 cancelled key的集合不是线程安全的,我记得标准文档就建议

    2018-06-16
    4
  • 洗头用酱油
    杨老师,有点迷糊,所以说一个对象偏向一个线程后,这个线程就有工作了优先权吗? 问题我记得不特殊设置的话,JVM是随机执行线程的呀?

    作者回复: 不是一个概念,biased其实用这种方式避免了锁,和线程调度是两件事

    2018-07-22
    1
收起评论
显示
设置
留言
32
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部