阿里二面:如何快速排查死锁?如何避免死锁?

(文末有惊喜)

前言

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

实例

死锁的本质,举个例子若是此时有一个线程 A ,按照先获持有锁 a 再获取锁 b的顺序得到锁,同时另一个线程 B,按照先获取锁 b 再获取锁 a 的顺序获取锁。以下图所示:程序员

接着咱们用代码模拟上线的执行过程bash

直接运行,发现主线程一直处于执行中,一直没法结束jvm

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

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

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

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

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

$ jstack 96521复制代码

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

死锁的代码是在DeadLock.java的32行和18行,此时咱们就能够去优化代码,解决死锁问题。测试

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

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

jconsole位于jdk的bin目录中spa

$ 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方法,该方法能够按照固定时长等待锁,所以线程能够在获取锁超时之后,主动释放以前已经得到的全部的锁。经过这种方式,也能够颇有效地避免死锁。

总结

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

---End---

来来来,喜欢就给个小关注呗,扫一扫送java全新整套java资料哦


相关文章
相关标签/搜索