java 分析java死锁

您是否曾经使用过java.util.concurrent.CountDownLatch ?

这是在两个或多个线程之间实现同步的非常方便的类,在该类中,一个或多个线程可以等待,直到在其他线程中执行的一组操作完成为止(请参阅javadoc和此文章 )。 在合适的情况下, CountDownLatch可以节省您的时间,您必须了解此类。

与往常一样,如果代码不好,线程同步会引发死锁。 并且由于并发用例可能非常复杂,因此开发人员必须非常小心。 在这里我不会描述复杂的并发问题,但是如果您不小心使用CountDownLatch ,可能会遇到一个简单的问题。

假设您有2个线程(线程1和线程2)共享一个java.util.concurrent.ArrayBlockingQueue,并且您想使用CountDownLatch对其进行同步。 检查以下简单示例:

package gr.qiozas.simple.threads.countdownlatch;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;public class DeadlockCaseCDL {public static void main(String[] args) throws InterruptedException {CountDownLatch c = new CountDownLatch(1);ArrayBlockingQueue b = new ArrayBlockingQueue(1);new Thread(new T1(c, b)).start();new Thread(new T2(c, b)).start();}private static class T1 implements Runnable {private CountDownLatch c;private ArrayBlockingQueue b;private T1(CountDownLatch c, ArrayBlockingQueue b) {this.c = c; this.b = b;}public void run() {try {b.put(234);b.put(654);doWork(T1.class);c.countDown();doWork(T1.class);} catch (InterruptedException ex) {}}}private static class T2 implements Runnable {private CountDownLatch c;private ArrayBlockingQueue b;private T2(CountDownLatch c, ArrayBlockingQueue b) {this.c = c; this.b = b;}public void run() {try {doWork(T2.class);c.await();doWork(T2.class);System.out.println("I just dequeue "+b.take());System.out.println("I just dequeue "+b.take());} catch (InterruptedException ex) {}}}private static void doWork(Class classz) {System.out.println(classz.getName()+" do the work");}
}

您在上面看到的是,主线程创建了一个计数为1的CountDownLatch。 和一个容量为“ 1”的ArrayBlockingQueue 然后生成“ 2个线程”。 ArrayBlockingQueue将用于实际的“工作”(入队和出队),而CountDownLatch将用于同步线程(入队必须在出队前完成)。

线程1使2条消息入队,线程2希望使它们出队,但仅在线程1使两条消息入队之后。 此同步由CountDownLatch保证。 您认为此代码可以吗? 不,这不是造成死锁的原因!

如果仔细看第10行,您将看到我初始化ArrayBlockingQueue的容量等于“ 1”。 但是线程1要排队2条消息,然后释放(CountDownLatch)的锁,以便随后被线程2占用。 容量“ 1? 队列中的1个线程阻塞Thread-1,直到另一个线程将一个消息从队列中出队,然后再次尝试使第二条消息入队。 不幸的是,只有线程2使消息从队列中出队,但是由于线程1拥有CountDownLatch锁,因此线程2无法使任何消息出队,因此它被阻塞了。 因此,由于两个线程都被阻塞(等待获取不同的锁),我们确实有一个死锁 。 线程1等待ArrayBlockingQueue锁定,而线程2等待CountDownLatch锁定(您也可以在下面的相关线程转储中看到它)。

如果我们增加队列的容量,那么此代码将毫无问题地运行,但这不是本文的重点。 您需要了解的是,必须谨慎使用CountDownLatch,以避免此类危险情况。 您必须了解您的类的功能情况,向团队的其他开发人员详细说明该功能,编写有用的javadoc,并始终编写在极端情况下(不仅对于快乐路径而言)都非常可靠的代码。

您可能需要帮助的另一点是,现代JVM无法检测到此死锁。 试试吧。

您可能知道,现代JVM(Hotspot和JRockit)都能够检测到简单的死锁,并在线程转储中报告它们。 请参阅从Hotspot JVM检测到的简单死锁示例:

Found one Java-level deadlock:
=============================
"Thread-6":
waiting to lock monitor 0x00a891ec (object 0x06c616e0, a java.lang.String),
which is held by "Thread-9"
"Thread-9":
waiting to lock monitor 0x00a8950c (object 0x06c61708, a java.lang.String),
which is held by "Thread-6"

您可以尝试DeadlockCaseCDL并获得线程转储(在GNU / Linux上仅运行“ kill -3 ‹jvm_pid›”)。 您会看到线程转储看起来很正常,并且JVM未检测到死锁,但是您处于死锁状态!!! 因此,请注意,JVM无法检测到这种死锁。

从我的本地执行中检查以下线程转储示例:

Full thread dump Java HotSpot(TM) Server VM (17.1-b03 mixed mode):"DestroyJavaVM" prio=10 tid=0x0946e800 nid=0x5382 waiting on condition [0x00000000]java.lang.Thread.State: RUNNABLE"Thread-1" prio=10 tid=0x094b1400 nid=0x5393 waiting on condition [0x7c79a000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for   (a java.util.concurrent.CountDownLatch$Sync)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:969)at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1281)at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:207)at gr.qiozas.simple.threads.countdownlatch.DeadlockCaseCDL$T2.run(DeadlockCaseCDL.java:50)at java.lang.Thread.run(Thread.java:662)"Thread-0" prio=10 tid=0x094afc00 nid=0x5392 waiting on condition [0x7c7eb000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for   (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)at java.util.concurrent.ArrayBlockingQueue.put(ArrayBlockingQueue.java:252)at gr.qiozas.simple.threads.countdownlatch.DeadlockCaseCDL$T1.run(DeadlockCaseCDL.java:29)at java.lang.Thread.run(Thread.java:662)"Low Memory Detector" daemon prio=10 tid=0x0947f800 nid=0x5390 runnable [0x00000000]java.lang.Thread.State: RUNNABLE"CompilerThread1" daemon prio=10 tid=0x7cfa9000 nid=0x538f waiting on condition [0x00000000]java.lang.Thread.State: RUNNABLE"CompilerThread0" daemon prio=10 tid=0x7cfa7000 nid=0x538e waiting on condition [0x00000000]java.lang.Thread.State: RUNNABLE"Signal Dispatcher" daemon prio=10 tid=0x7cfa5800 nid=0x538d waiting on condition [0x00000000]java.lang.Thread.State: RUNNABLE"Finalizer" daemon prio=10 tid=0x7cf96000 nid=0x538c in Object.wait() [0x7cd15000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on  (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)- locked  (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)"Reference Handler" daemon prio=10 tid=0x7cf94800 nid=0x538b in Object.wait() [0x7cd66000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on  (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:485)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)- locked  (a java.lang.ref.Reference$Lock)"VM Thread" prio=10 tid=0x7cf92000 nid=0x538a runnable"GC task thread#0 (ParallelGC)" prio=10 tid=0x09475c00 nid=0x5383 runnable"GC task thread#1 (ParallelGC)" prio=10 tid=0x09477000 nid=0x5384 runnable"GC task thread#2 (ParallelGC)" prio=10 tid=0x09478800 nid=0x5385 runnable"GC task thread#3 (ParallelGC)" prio=10 tid=0x0947a000 nid=0x5387 runnable"VM Periodic Task Thread" prio=10 tid=0x09489800 nid=0x5391 waiting on conditionJNI global references: 854HeapPSYoungGen      total 14976K, used 1029K [0xa2dd0000, 0xa3e80000, 0xb39d0000)eden space 12864K, 8% used [0xa2dd0000,0xa2ed1530,0xa3a60000)from space 2112K, 0% used [0xa3c70000,0xa3c70000,0xa3e80000)to   space 2112K, 0% used [0xa3a60000,0xa3a60000,0xa3c70000)PSOldGen        total 34304K, used 0K [0x815d0000, 0x83750000, 0xa2dd0000)object space 34304K, 0% used [0x815d0000,0x815d0000,0x83750000)PSPermGen       total 16384K, used 1739K [0x7d5d0000, 0x7e5d0000, 0x815d0000)object space 16384K, 10% used [0x7d5d0000,0x7d782e90,0x7e5d0000)

参考: 有益的CountDownLatch和我们的JCG合作伙伴 Adrianos Dadis 遇到的棘手的Java僵局 ,位于“ Java,集成和源代码的优点”博客上 。

相关文章 :
  • Java并发教程– CountDownLatch
  • 并发优化–减少锁粒度
  • Java内存模型-快速概述和注意事项
  • Java并发教程–线程池
  • Java并发教程–信号量
  • Java教程和Android教程列表

翻译自: https://www.javacodegeeks.com/2011/11/beneficial-countdownlatch-and-tricky.html

java 分析java死锁

java 分析java死锁_有益的CountDownLatch和棘手的Java死锁相关推荐

  1. 有益的CountDownLatch和棘手的Java死锁

    您是否曾经使用过java.util.concurrent.CountDownLatch ? 这是在两个或多个线程之间实现同步的非常方便的类,在该类中,一个或多个线程可以等待,直到在其他线程中执行的一组 ...

  2. java 分析jstack日志_望闻问切使用jstack和jmap剖析java进程各种疑难杂症

    最近碰到多起java程序导致服务器cpu使用率100%的情况,下面把排查解决方法记录下来. 其实遇到这种情况,首先要保持冷静的头脑,遇事不乱.然后望闻问切,找到病根,直达病灶.所谓望闻问切就是,首先使 ...

  3. java高深技术总结_一名25K以上的高薪Java程序员总结出的技术以及学习技能

    原标题:一名25K以上的高薪Java程序员总结出的技术以及学习技能 总所周知,Java是目前使用最为广泛的网络编程语言之一. 它具有简单,面向对象,稳定,与平台无关,解释型,多线程,动态等特点. 一般 ...

  4. 百度java的线程技术_自我提升(基础技术篇)——java线程简介

    前言:虽然自己平时都在用多线程,也能完成基本的工作需求,但总觉得,还是对线程没有一个系统的概念,所以,查阅了一些资料,理解那些大神和官方的资料,写这么一篇关于线程的文章 本来想废话一番,讲讲自己的经历 ...

  5. java职业发展路线图_从程序员到CTO的Java技术路线图 JAVA职业规划 JAVA职业发展路线图 系统后台框架图、前端工程师技能图 B2C电子商务基础系统架构解析...

    http://zz563143188.iteye.com/blog/1877266在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样 ...

  6. java se13安装教程_在Linux发行版中安装Java 13/OpenJDK 13的方法

    本文介绍在Linux发行版Ubuntu 18.04/16.04.Debian 10/9.CentOS 7/8.Fedora 31/30/29中安装Java 13/OpenJDK 13.Java SE ...

  7. java增删改查_只会增删改查的Java程序员该如何发展

    首先,对于当前的Java程序员来说,要想在软件开发领域走得更远,应该做好三件事,其一是为自己设定一个主攻方向,其二是根据自身的知识基础和能力特点来制定学习计划,其三是注重行业发展趋势,积极拥抱新技术. ...

  8. java 删除桌面快捷方式_能否在桌面创建快捷方式运行java程序?

    能否在桌面创建快捷方式运行java程序? 来源:互联网  宽屏版  评论 2009-05-07 07:51:17 分类: 电脑/网络 >> 程序设计 >> 其他编程语言 问题描 ...

  9. java局域网聊天代码_简单的局域网聊天程序(java版本的)

    局域网聊天程序,首先我已经默认你的电脑已经配置好的java开发的一些环境,所需代码有两个java的源代码,他们分别是1:Server_Test.java-------2:Socket_Test.jav ...

最新文章

  1. 说AI没有创造性?现在它都能创作鬼畜音乐了
  2. 新工作总结之权限系统设计
  3. Opengl-光照-基本光照-冯氏(千万好好理解后面所有的延伸基本都是基于这个的)
  4. Netty详解(六):Netty 编解码技术
  5. Angular - - $cacheFactory
  6. DBGrid 应用全书
  7. JavaScript 基础一
  8. 更改画面_看够联想姨妈红?阿虚教你更改ThinkPad 开机画面
  9. Team Viewer 远程链接一直显示-正在初始化显示参数
  10. CAD导出.eps格式图
  11. android仿微信红包动画,如何在Android中实现一个硬币转动微信红包动画效果
  12. 集合A和集合B的并运算图示
  13. 《读者》的“卷首语” (五)
  14. idou老师教你学istio2:监控能力介绍
  15. php base64 转 amr,base64转amr文件
  16. lumen php命令,lumen添加artisan 命令方法
  17. WHQL认证(徽标认证)步骤介绍
  18. Android之四大组件之一-BroadcastReceiver的使用(二)
  19. python打开文本文档时不允许其他程序修改_2.2.4 python 文件处理 - 文件其他操作修改...
  20. StudyFlutter——我的第一个APP

热门文章

  1. JS中函数和变量声明的提升
  2. linux将光驱挂载到目录下,Linux操作系统下关于光驱的挂载
  3. mybatis-plus 错误java.lang.NoClassDefFoundError: org/apache/velocity/context/Context
  4. pythonnumpy教程_Python教程:numpy的基本介绍
  5. 把本地库推送到github远程库
  6. elasticsearch7常见查询(term、match、bool、filter)
  7. MySQL存储过程+游标+触发器
  8. 页面残留数据该如何处理
  9. 设计模式 原型模式_创新设计模式:原型模式
  10. spring 计划任务_与Spring的计划任务一起按时运行