面试官:如何快速排查死锁?如何避免死锁?

前言

相信程序员都会碰上这样的问题,Java死如何排查?又如何解决呢?那么,何为死锁呢?死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。今天一次性来帮助大家解决Java死锁的有关问题。

实例

死锁的本质,举个例子如果此时有一个线程 A ,按照先获持有锁 a 再获取锁 b的顺序获得锁,同时另外一个线程 B,按照先获取锁 b 再获取锁 a 的顺序获取锁。如下图所示: 面试官:如何快速排查死锁?如何避免死锁?

接着我们用代码模拟上线的执行过程 面试官:如何快速排查死锁?如何避免死锁?

直接运行,发现主线程一直处于执行中,一直无法结束 面试官:如何快速排查死锁?如何避免死锁?

通过jdk工具jps、jstack排查死锁问题

步骤一:使用jsp查找程序进行

jps:jdk提供的一个工具,可以查看到正在运行的java进程

面试官:如何快速排查死锁?如何避免死锁?

步骤二:使用jstack查看线程堆栈信息

jstack:jdk提供的一个工具,可以查看java进程中线程堆栈信息。更详细的用法见文档最后。

$ jstack 96521复制代码

面试官:如何快速排查死锁?如何避免死锁?

从上面的堆栈信息中我们可以发现这个内容:“Found one Java-level deadlock”,表示程序中发现了一个死锁,后面包含更多详细的信息,重点下面:

面试官:如何快速排查死锁?如何避免死锁?

死锁的代码是在DeadLock.java的32行和18行,此时我们就可以去优化代码,解决死锁问题。

通过jdk提供的工具jconsole排查死锁问题

jconsole:jdk提供的一个可视化的工具,方便排查程序的一些问题,如:程序内存溢出、死锁问题等等。更详细的用法见文档最后。jconsole位于jdk的bin目录

$ jconsole复制代码

面试官:如何快速排查死锁?如何避免死锁?

可以看到我们的程序,点击连接。

在jconsole窗口中查看线程堆栈信息

点击“检测死锁”,可以看到程序死锁信息

面试官:如何快速排查死锁?如何避免死锁? 面试官:如何快速排查死锁?如何避免死锁?

上图中可以看到详细的死锁信息,和jstack中信息类似。

通过jdk提供的工具VisualVM排查死锁问题

VisualVM:jdk提供的一个非常强大的排查java程序问题的一个工具,可以监控程序的性能、查看jvm配置信息、堆快照、线程堆栈信息。算是程序优化的必备工具。工具位于jdk的bin目录中。

$ jvisualvm复制代码

面试官:如何快速排查死锁?如何避免死锁?

切换到“线程”窗口

面试官:如何快速排查死锁?如何避免死锁?

执行提示有死锁情况。在线程窗口中点击“线程Dump”按钮。

查看堆栈信息

面试官:如何快速排查死锁?如何避免死锁?

线程堆栈快照的信息和jstack查看到的信息一样,即可发现死锁代码。

如何避免死锁?

我们知道了 死锁如何产生的 ,那么就知道该如何去预防。 如果一个线程每次只能获取一个锁,那么就不会出现由于嵌套持有锁顺序导致的死锁

1. 正确的顺序获得锁

如果必须获取多个锁,我们就要考虑不同线程获取锁的顺序。

上面的例子出现 死锁的根本原因就是获取所的顺序是乱序 的,超乎我们控制的。上面例子最理想的情况就是把业务逻辑抽离出来, 把获取锁的代码放在一个公共的方法里面,让这两个线程获取锁都是从我的公共的方法里面获取。

当Thread1线程进入公共方法时,获取了A锁,另外Thread2又进来了,但是A锁已经被Thread1线程获取了,所以只能阻塞等待。Thread1接着又获取锁B,Thread2线程就不能再获取不到了锁A,更别说再去获取锁B了,这样就有一定的顺序了。只有当线程1释放了所有锁,线程B才能获取。

比如前面的例子我们改成

面试官:如何快速排查死锁?如何避免死锁?

查看打印结果,我们发现 线程0 获取成功然后线程1才能继续获取 面试官:如何快速排查死锁?如何避免死锁?

2. 超时放弃

当线程获取锁超时了则放弃,这样就避免了出现死锁获取的情况。当使用synchronized关键词提供的内置锁时,只要线程没有获得锁,那么就会永远等待下去, 然而Lock接口提供了boolean tryLock(long time, TimeUnit unit) throws InterruptedException方法 ,该方法可以按照固定时长等待锁, 因此线程可以在获取锁超时以后 ,主动释放之前已经获得的所有的锁。通过这种方式,也可以很有效地避免死锁。

总结

死锁就是“两个任务以不合理的顺序互相争夺资源”造成 ,因此为了规避死锁,应用程序需要妥善处理资源获取的顺序。另外有些时候,死锁并不会马上在应用程序中体现出来, 在通常情况下,都是应用在生产环境运行了一段时间后,才开始慢慢显现出来 ,在实际测试过程中,由于死锁的隐蔽性,很难在测试过程中及时发现死锁的存在, 而且在生产环境中应用出现了死锁,往往都是在应用状况最糟糕的时候——在高负载情况下 。因此,开发者开发过程中要谨慎分析每个系统资源的使用情况,合理规避死锁。

来源于:https://mp.weixin.qq.com/s/98KzwNQhBCdVVtPfg9GFXA

原文 

https://juejin.im/post/5e786bcce51d45761319541c

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 面试官:如何快速排查死锁?如何避免死锁?

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址