实践讲解死锁及死锁检测(图+文+代码) | 您所在的位置:网站首页 › 检测apk是否有死锁 › 实践讲解死锁及死锁检测(图+文+代码) |
1 缘起
在学习ArrayBlockingQueue(ABQ)的过程中, 实现队列阻塞相关的功能是通过java.util.concurrent.locks.Condition, 如enqueue的notEmpty和dequeue的notFull均是Condition, 通过await实现等待,这里我由此想到了中断线程的知识, 通过翻阅java.lang.Thread源码发现,Thread.stop、Thread.suspend和Thread.resume均被JDK1.8标记为Deprecated, 源码中给出了说明文档:https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html, 说是多线程间不安全,可能形成死锁, 于是,我就自己通过代码实现了一下死锁, 同时,结合示意图以及时间序列图分析讲解死锁, 并给出了死锁分析工具jconsole的是使用案例, 检测运行的Java服务中是否有死锁,以及出现死锁的线程, 帮助读者轻松应对知识考核与交流。 2 死锁多个线程间相互申请锁住对方尚未释放的资源,如对象,方法等, 线程间依赖等待对方释放资源,造成的死循环。 死锁图例如下图所示, 图中展示了线程T1和线程T2分别申请对象A和对象B而造成的死锁, 初始化阶段,线程T1有对象A,线程T2持有对象B, 死锁阶段,线程T1在线程T2持有对象B的阶段申请锁住对象B, 线程T2在线程T1持有对象A的阶段申请锁住对象A, 由于线程在各自占有资源的情况下,相互申请对方持有的资源, 双方都不会退出资源申请,形成环形等待,即死锁。 下面以时序分解的方式分析死锁,过程如下图所示。 约定:线程T1,线程T2,对象A,对象B 线程T1占有对象A的时间段:[t1, t1+4] 线程T2占有对象B的时间段:[t1+1, t1+4] 线程T1在t1+2时刻申请对象B,此时对象B仍被线程T2持有,线程T1若想申请并锁住对象B,需要等到线程T2释放对象B, 线程T2在t1+3时刻申请对象A,此时对象A仍被线程T1持有,线程T2若想申请并锁住对象A,需要等到线程T1释放对象A, 然而在线程各自占有资源期间,申请了对方尚未释放的资源,相互等待,形成等待环,即死锁。 jconsole是JDK(1.8)自带的工具,安装JDK后可直接使用,控制台输入jconsole即可调用jconsole客户端, 图形界面如下图所示。 由图可知,jconsole监控了运行的Java进程,既可以连接本地Java进行,又可以连接远程的Java进程, 这里选择DeadLockTest测试死锁的Java进程,并连接。 本地Java进程没有配置SSL安全连接,因此jconsole连接时会提示非安全连接, 如下图所示,这里选择不安全的连接,连接DeadLockTest进程。 进入监控页面后,选择线程属性,如下图所示, 下方有检测死锁的按钮,点击即可检测当前Java进程中的死锁。 检测死锁后,发现该DeadLockTest进程中存在死锁线程, 如下图所示,发生死锁的线程为Thread-1和Thread-2。 初始化: 线程Thread-1持有对象A(UserEntity@27b4a46d) 线程Thread-2持有对象B(UserEntity@37a0d490) ![]() ![]() (1)死锁:多个线程间相互申请锁住对方尚未释放的资源,如对象,方法等,线程间依赖等待对方释放资源,造成的死循环。 (2)Thread以标记弃用:Thread.suspend、Thread.resume和Thread.stop,因会造成死锁; (3)Thread停止推荐使用Thread.interrupt。 |
CopyRight 2018-2019 实验室设备网 版权所有 |