死锁是两个或多个线程永远被阻塞的编程情况,这种情况发生在至少两个线程和两个或更多资源的情况下。 在这里,我编写了一个简单的程序,该程序将导致死锁情况,然后我们将看到如何对其进行分析。

Java死锁示例

package com.journaldev.threads;
public class ThreadDeadlock {public static void main(String[] args) throws InterruptedException {Object obj1 = new Object();Object obj2 = new Object();Object obj3 = new Object();Thread t1 = new Thread(new SyncThread(obj1, obj2), 't1');Thread t2 = new Thread(new SyncThread(obj2, obj3), 't2');Thread t3 = new Thread(new SyncThread(obj3, obj1), 't3');t1.start();Thread.sleep(5000);t2.start();Thread.sleep(5000);t3.start();}
}
class SyncThread implements Runnable{private Object obj1;private Object obj2;public SyncThread(Object o1, Object o2){this.obj1=o1;this.obj2=o2;}@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + ' acquiring lock on '+obj1);synchronized (obj1) {System.out.println(name + ' acquired lock on '+obj1);work();System.out.println(name + ' acquiring lock on '+obj2);synchronized (obj2) {System.out.println(name + ' acquired lock on '+obj2);work();}System.out.println(name + ' released lock on '+obj2);}System.out.println(name + ' released lock on '+obj1);System.out.println(name + ' finished execution.');}private void work() {try {Thread.sleep(30000);} catch (InterruptedException e) {e.printStackTrace();}}
}

在上面的程序中,SyncThread实现了Runnable接口,并且通过使用同步块逐个获取每个对象上的锁,从而对两个对象起作用。

在main方法中,我为SyncThread运行了三个线程,并且每个线程之间都有一个共享资源。 线程以这样的方式运行:它将能够获取第一个对象的锁定,但是当它试图获取第二个对象的锁定时,它将进入等待状态,因为它已经被另一个线程锁定了。 这对导致死锁的线程之间的资源形成了循环依赖性。

当我执行上面的程序时,这是生成的输出,但是由于死锁,程序永远不会终止。

t1 acquiring lock on java.lang.Object@6d9dd520
t1 acquired lock on java.lang.Object@6d9dd520
t2 acquiring lock on java.lang.Object@22aed3a5
t2 acquired lock on java.lang.Object@22aed3a5
t3 acquiring lock on java.lang.Object@218c2661
t3 acquired lock on java.lang.Object@218c2661
t1 acquiring lock on java.lang.Object@22aed3a5
t2 acquiring lock on java.lang.Object@218c2661
t3 acquiring lock on java.lang.Object@6d9dd520

在这里,我们可以从输出中清楚地确定死锁情况,但是在实际应用中,很难找到死锁情况并对其进行调试。

分析死锁

要分析死锁,我们需要查看应用程序的Java线程转储 ,在上一篇文章中,我解释了如何使用VisualVM Profiler或jstack实用程序生成线程转储 。

这是上面程序的线程转储。

2012-12-27 19:08:34
Full thread dump Java HotSpot(TM) 64-Bit Server VM (23.5-b02 mixed mode):
'Attach Listener' daemon prio=5 tid=0x00007fb0a2814000 nid=0x4007 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'DestroyJavaVM' prio=5 tid=0x00007fb0a2801000 nid=0x1703 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE
't3' prio=5 tid=0x00007fb0a204b000 nid=0x4d07 waiting for monitor entry [0x000000015d971000]java.lang.Thread.State: BLOCKED (on object monitor)at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f658> (a java.lang.Object)- locked <0x000000013df2f678> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
't2' prio=5 tid=0x00007fb0a1073000 nid=0x4207 waiting for monitor entry [0x000000015d209000]java.lang.Thread.State: BLOCKED (on object monitor)at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f678> (a java.lang.Object)- locked <0x000000013df2f668> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
't1' prio=5 tid=0x00007fb0a1072000 nid=0x5503 waiting for monitor entry [0x000000015d86e000]java.lang.Thread.State: BLOCKED (on object monitor)at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f668> (a java.lang.Object)- locked <0x000000013df2f658> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
'Service Thread' daemon prio=5 tid=0x00007fb0a1038000 nid=0x5303 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'C2 CompilerThread1' daemon prio=5 tid=0x00007fb0a1037000 nid=0x5203 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'C2 CompilerThread0' daemon prio=5 tid=0x00007fb0a1016000 nid=0x5103 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'Signal Dispatcher' daemon prio=5 tid=0x00007fb0a4003000 nid=0x5003 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE
'Finalizer' daemon prio=5 tid=0x00007fb0a4800000 nid=0x3f03 in Object.wait() [0x000000015d0c0000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000013de75798> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)- locked <0x000000013de75798> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)
'Reference Handler' daemon prio=5 tid=0x00007fb0a4002000 nid=0x3e03 in Object.wait() [0x000000015cfbd000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000013de75320> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:503)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)- locked <0x000000013de75320> (a java.lang.ref.Reference$Lock)
'VM Thread' prio=5 tid=0x00007fb0a2049800 nid=0x3d03 runnable
'GC task thread#0 (ParallelGC)' prio=5 tid=0x00007fb0a300d800 nid=0x3503 runnable
'GC task thread#1 (ParallelGC)' prio=5 tid=0x00007fb0a2001800 nid=0x3603 runnable
'GC task thread#2 (ParallelGC)' prio=5 tid=0x00007fb0a2003800 nid=0x3703 runnable
'GC task thread#3 (ParallelGC)' prio=5 tid=0x00007fb0a2004000 nid=0x3803 runnable
'GC task thread#4 (ParallelGC)' prio=5 tid=0x00007fb0a2005000 nid=0x3903 runnable
'GC task thread#5 (ParallelGC)' prio=5 tid=0x00007fb0a2005800 nid=0x3a03 runnable
'GC task thread#6 (ParallelGC)' prio=5 tid=0x00007fb0a2006000 nid=0x3b03 runnable
'GC task thread#7 (ParallelGC)' prio=5 tid=0x00007fb0a2006800 nid=0x3c03 runnable
'VM Periodic Task Thread' prio=5 tid=0x00007fb0a1015000 nid=0x5403 waiting on condition
JNI global references: 114
Found one Java-level deadlock:
=============================
't3':waiting to lock monitor 0x00007fb0a1074b08 (object 0x000000013df2f658, a java.lang.Object),which is held by 't1'
't1':waiting to lock monitor 0x00007fb0a1010f08 (object 0x000000013df2f668, a java.lang.Object),which is held by 't2'
't2':waiting to lock monitor 0x00007fb0a1012360 (object 0x000000013df2f678, a java.lang.Object),which is held by 't3'
Java stack information for the threads listed above:
===================================================
't3':at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f658> (a java.lang.Object)- locked <0x000000013df2f678> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
't1':at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f668> (a java.lang.Object)- locked <0x000000013df2f658> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
't2':at com.journaldev.threads.SyncThread.run(ThreadDeadlock.java:41)- waiting to lock <0x000000013df2f678> (a java.lang.Object)- locked <0x000000013df2f668> (a java.lang.Object)at java.lang.Thread.run(Thread.java:722)
Found 1 deadlock.

线程转储输出清楚地显示了死锁情况,并且所涉及的线程和资源导致了死锁情况。

为了分析死锁,我们需要找出状态为BLOCKED的线程,然后寻找它正在等待锁定的资源,每个资源都有一个唯一的ID,通过它我们可以找到哪个线程已经在对象上保持了锁定。 例如,线程“ t3”正在等待锁定0x000000013df2f658,但它已被线程“ t1”锁定。

一旦我们分析了死锁情况并找出了导致死锁的线程,就需要进行代码更改以避免死锁情况。

避免死锁

这些是我们可以避免大多数僵局情况的一些准则。

  • 避免嵌套锁 :这是造成死锁的最常见原因,如果已经持有另一个资源,请避免锁定另一个资源。 如果仅使用一个对象锁,则几乎不可能出现死锁情况。 例如,这是不带嵌套锁的run()方法的另一种实现,并且程序成功运行且没有死锁情况。

    public void run() {String name = Thread.currentThread().getName();System.out.println(name + ' acquiring lock on ' + obj1);synchronized (obj1) {System.out.println(name + ' acquired lock on ' + obj1);work();}System.out.println(name + ' released lock on ' + obj1);System.out.println(name + ' acquiring lock on ' + obj2);synchronized (obj2) {System.out.println(name + ' acquired lock on ' + obj2);work();}System.out.println(name + ' released lock on ' + obj2);System.out.println(name + ' finished execution.');}
  • 仅锁定所需条件 :您应该仅对必须处理的资源获得锁定,例如,在上述程序中,我正在锁定完整的Object资源,但是如果我们仅对其中一个字段感兴趣,则应仅锁定该对象具体字段不完整的对象。
  • 避免无限期地等待 :如果两个线程正在使用线程连接无限期地等待彼此完成,则可能会陷入死锁。 如果您的线程必须等待另一个线程完成,则始终最好使用join,并在等待线程完成的最长时间内使用它。

参考: Java死锁示例–如何从开发人员食谱博客的JCG合作伙伴 Pankaj Kumar中分析死锁情况 。

翻译自: https://www.javacodegeeks.com/2013/01/java-deadlock-example-how-to-analyze-deadlock-situation.html

Java死锁示例–如何分析死锁情况相关推荐

  1. java 分析java死锁_Java死锁示例–如何分析死锁情况

    java 分析java死锁 死锁是两个线程或多个线程永远被阻塞的编程情况,这种情况发生在至少两个线程和两个或更多资源的情况下. 在这里,我编写了一个简单的程序,它将导致死锁情况,然后我们将看到如何对其 ...

  2. DllMain中不当操作导致死锁问题的分析--死锁介绍

    最近在网上看到一些关于在DllMain中不当操作导致死锁的问题,也没找到比较确切的解答,这极大吸引了我研究这个问题的兴趣.我花了一点时间研究了下,正好也趁机研究了下进程对DllMain的调用规律.因为 ...

  3. DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子

    有了前面两节的基础,我们现在切入正题:研究下DllMain为什么会因为不当操作导致死锁的问题.首先我们看一段比较经典的"DllMain中死锁"代码.(转载请指明出于breaksof ...

  4. 死锁概念?如何分析死锁和避免死锁?

    什么是死锁?如何分析死锁和避免死锁? 死锁就是在多线程运行时,线程对象在获取操作资源时,操作资源被其他线程对象占用而获取不到,导致线程运行阻塞 首先用jsp命令查看当前进程pid是否发生死锁,然后利用 ...

  5. 死锁是什么?死锁产生的条件?如何避免死锁?以及死锁的示例代码(Java代码)

    文章目录 一.什么是死锁? 二.产生死锁的条件? 三.产生死锁的示例代码(java) 四.如何避免死锁? 一.什么是死锁? 下面图片参考 JavaGuide中的内容: 死锁的概念: 死锁:指的是相互两 ...

  6. Innodb锁系统 Insert/Delete 锁处理及死锁示例分析

    A.INSERT 插入操作在函数btr_cur_optimistic_insert->btr_cur_ins_lock_and_undo->lock_rec_insert_check_an ...

  7. 死锁示例代码_Java示例中的死锁

    死锁示例代码 Deadlock in java is a programming situation where two or more threads are blocked forever. Ja ...

  8. Java 线程死锁及如何避免死锁介绍

    线程死锁 1. 什么是线程死锁 2. 死锁产生的原因 3. 如何避免线程死锁. 1. 什么是线程死锁 死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现象,在无外力作用的情况下, ...

  9. Java:多线程(同步死锁、锁原子变量、线程通信、线程池)

    5,同步和死锁 5.1,线程同步 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象: 修饰一个方法,被修饰的方法称为同步方法,其作用 ...

最新文章

  1. 线性回归之模型的保存和加载
  2. 关于学习Python的一点学习总结(20->assert判断->while和for使用)
  3. The application does not contain a valid bundle identifier.解决方法
  4. 【深度学习】深入浅出神经网络框架的模型元件(池化、正则化和反卷积层)
  5. AI:IPPR的模式生成-CNN模块学习/训练方式(基本结构)
  6. Sublime Text怎么快速建立一个html5页面模板
  7. 骑士游历问题问题_骑士步行问题
  8. java 配置hdfs集群_Hadoop集群搭建-04安装配置HDFS
  9. 2440 linux文件写,添加yaffs2文件系统 - Linux2.6.39在S3C2440上的移植_Linux编程_Linux公社-Linux系统门户网站...
  10. isset php 二维数组_php 数组去重,一维数组去重,二维数组去重
  11. 使用zend studio配置Xdebug调试PHP教程
  12. 64位内核第三讲,Windbg的使用.以及命令
  13. 老路教你用得上的商学课_系列笔记
  14. 程序员写书到底赚钱吗
  15. 2018美日科学家因免疫治疗得诺贝尔生理医学奖|动图展示历年生理学奖
  16. 失业七个月,面试六十家公司的深圳体验(转贴)
  17. JavaScript 每日一题 #8
  18. Mc1.16forge官混教程/教补-#3 物品材质覆盖注意要点[分支1]
  19. ipa包的简单校验方法
  20. mysql where 条件取反_MySQL搜索: WHERE 多条件

热门文章

  1. browserquest php安装,请问一下browserquest-php项目换成GatewayWorker的形式需要怎么部署worker...
  2. java作为kafka生产者实验及Expiring超时问题解决
  3. ReviewForJob——快速排序(基于插入排序)+快速选择(快速排序变体)
  4. java 邮件 tls_通过TLS发送的Java邮件
  5. 技术停滞_检测和测试停滞的流– RxJava常见问题解答
  6. dynamodb容器使用_使用DynamoDB映射器将DynamoDB项目映射到对象
  7. 开源java性能分析工具_Java性能监控:您应该知道的5个开源工具
  8. jax-ws和jax-rs_JAX-RS和JSON-P集成
  9. apache lucene_Apache Lucene的结构
  10. c语言中如何让诊断代码右移_如何检测和诊断生产中的慢代码