一文学会 Java 死锁和 CPU 100% 问题的排查技巧

Java 死锁排查和解决
要排查和解决死锁,首先思考三个问题:
什么是死锁?
为什么会出现死锁?
怎么排查代码中出现了死锁?
如何避免写出死锁的代码?
作为技术人员(工程师),在出现问题的时候,能够尽快的去解决这个问题。但是在学习技术知识的时候,还是脚踏实地,多问一些为什么,一个好的问题,能够让自己思考,这方面的能力也一定要锻炼锻炼哦,这样才能更好的理解和掌握知识,并探究/触碰到更深入的地方。
啥是死锁?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

注:进程和线程都可以发生死锁,只要满足死锁的条件!
为啥子会出现死锁?
从上面的概念中我们知道
(1)必须是两个或者两个以上进程(线程)
(2)必须有竞争资源
怎么排查代码中出现了死锁?【重点来了】
首先整一个死锁的代码,看例子:

上面这段代码执行后,就会出现死锁,排查的姿势有如下几种,搞起来吧!
第一个姿势:使用 jps + jstack
一:在 windons 命令窗口,使用jps -l
【不会使用 jps 请自行查询资料】

二:使用 jstack -l 12316
【不会使用 jstack 请自行查询资料】

第二个姿势:使用 jconsole
在 window 打开 JConsole,JConsole 是一个图形化的监控工具!
一:在 windons 命令窗口 ,输出JConsole
,如下图:

二:选择到线程的 tab 上,如下截图。

第三个姿势:使用 Java Visual VM
在 window 打开 jvisualvm,jvisualvm 是一个图形化的监控工具!
一:在 windons 命令窗口 ,输出 jvisualvm

二:依然是切换到线程这个 TAB 上,很明显的就有提示!

如何避免死锁?
上面说了死锁出现的原因以及通过三种方式来检测和排查死锁,下面更重要的东西来了,就是如何避免死锁,如果能够让写出的代码避免死锁出现也就没有上面这些排查的过程了。最好的是从源头控制问题,而不是后期遇到问题在去填坑。
我看了阿里巴巴中最新的开发规约,里面有对避免死锁的说明,具体如下:
【强制】对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会 造成死锁。说明:线程一需要对表 A、B、C 依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序也必须是 A、B、C,否则可能出现死锁。
Java CPU 100% 排查技巧
第一个姿势,步骤有点多,难度四星
平时多积累一点,这样在遇到问题的时候就少句求人的话。如果在实际的开发中遇到 CPU 100%问题,要怎么排查呢?如果你没有遇到过这个问题,请先自己思考 10s,如果你遇到过,这个时候也正好可以在回顾一遍。
一、 使用 top 命令查看 cpu 占用资源较高的 PID

当前占用 cup100% 的 PID 为 3455。
二、通过 jps 找到当前用户下的 java 程序 PID
执行 jps -l 能够打印出所有的应用的 PID,找到有一个 PID 和这个 cpu 使用 100%一样的 ID!!!就知道是哪一个服务了。知道了对应的服务,在接着后续的分析步骤。
三、 使用 pidstat -p < PID > 1 3 -u -t


四、找到 cpu 占用较高的线程 TID ,通过上图发现是 3467 的 TID 占用 cup 较大
五、 因为 jstack 命令输出文件记录的线程 ID 是 16 进制。因此我们先将 TID 转换为十六进制的表示方式,转换方式可以参考下图。
将 3467 转为十六进制 d8d,注意是小写!! 记录下来,后面会使用。

六、通过 jstack [-l] PID 输出当前进程的线程信息
七、查找 TID 对应的线程(输出的线程 id 为十六进制),找到对应的代码,使用命令查找哦,不要肉眼比对,具体命令请思考,给你表现机会。

找到之后具体分析这个线程在干什么,为什么会占用这么多的 CUP 资源。
PS:线程的几种状态如下说明:
推荐两个高效排查问题工具
一 :show-busy-java-threads

简单安装和使用过程:
1.下载 show-busy-java-threads[2]
2.上传服务器,然后进行解压
3.然后执行对应的命令

二:阿里开源的问题定位神器 arthas 来定位问题。
这个里面有很多命令,如 thread 支持一键展示当前最忙的前 N 个线程并打印堆栈,最简单的 thread -n 10 即可将最忙碌的十个线程快照打印出来,真正高效。

定位神器 arthas 安装过程就不做介绍了,如果你还没有用过这个工具,我建议一定去用一下,说不定你会爱上它!
总结
本文内容比较多,基本上是手把手的教程了,希望能够对你有所帮助,也建议没有遇到类似问题的伙伴,看完之后一定要亲自去实践一下操作过程(有些姿势光看不用是不行的),如果没有环境可以自行想办法搞一个测试例子。还是老话:不要眼高手低,看了和做了本质上两个概念,最终收获的也一定不同。
彩蛋-另一个姿势
也可以通过使用 jstack 找到系统的代码性能问题
1、在进行压力测试的时候,使用 jps 找到应用的 PID
2、然后使用 jstack 输出出压力测试时候应用的 dump 信息
3、分析输出的日志文件中那个方法 block 线程占用最多,这里可能是性能有问题,找到对应的代码分析
看完三件事❤️
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
关注公众号 『 java 烂猪皮 』,不定期分享原创知识。
同时可以期待后续文章 ing🚀
.关注后回复【666】扫码即可获取学习资料包

作者:阿飞云
链接:https://club.perfma.com/article/2139156
评论