java 分析java死锁_有益的CountDownLatch和棘手的Java死锁

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死锁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/358629.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

验证码识别Burp reCAPTCHA插件使用

介绍 Burp的reCAPTCHA也可用来识别验证码,github地址:https://github.com/bit4woo/reCAPTCHA,下载相应的jar包添加到burp中,位置在extender-extensions-add下,添加成功后burp模块栏会多出reCAPTCHA一栏,如下…

linux下的五种io模型,Linux下的五种IO模型

Java中提供的IO有关的API,在文件处理的时候,其实依赖操作系统层面的IO操作实现的(关于Java对IO的三种封装,可见我的另一篇博客)开门见山,Linux下的如中IO模型:阻塞IO模型,非阻塞IO模型,IO复用模…

怎么样才能玩转前端所有的CSS背景相关问题?

目录 背景颜色 背景图像 背景图像 - 水平或垂直平铺 背景图像- 设置定位与不平铺 背景- 简写属性 CSS 背景属性 CSS 背景 CSS 背景属性用于定义HTML元素的背景。 CSS 属性定义背景效果: background-

如何使用Eclipse调试Maven构建

当运行带有许多插件(例如jOOQ或Flyway插件 )的Maven构建时,您可能想更深入地了解这些插件或这些插件的扩展内部发生了什么。 当您从命令行运行Maven时,这可能并不明显,例如通过: C:\Users\jOOQ\workspace&…

PropertyGrid 控件使用方法

编写一个对象,后面传递给 PropertyGrid 来显示: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; namespace WindowsForms_PropertyGrid {public class UserPropertyClass{privat…

BurpSuite插件 -- Struts2-RCE

​好遗憾,明明不想失去,却又无能为力,说真的,那种想放弃又想爱的滋味,真折磨人。。。。 ---- 网易云热评 一、插件介绍 一个用于检查struts2 RCE漏洞的Burp扩展器 二、下载地址(插件作者:prakh…

c语言移位运算的作用,C语言的移位操作符使用方法

位移位运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算。位移位运算符分为左移和右移两种,均为双目运算符。第一运算对象是移位对象,第二个运算对象是所移的二进制位数。以下是小编为大家搜索整理的C语言的移位操作符使用方法…

一文精通CSS文本问题,你值得一看

目录 CSS 文本格式 文本颜色 文本的对齐方式 文本修饰 文本转换 文本缩进 CSS文本属性 CSS 文本格式 下面是文本的演示

[算法导论]练习16.1-4 活动教室分配(区间着色问题)

转载请注明原创:http://www.cnblogs.com/StartoverX/p/4608412.html 题目: 有一组活动,我们需要将它们安排到一些教室,任意活动都可以在任意教室进行。我们希望使用最少的教室完成所有活动。 设计一个高效的贪心算法求每个活动应该…

c语言选择菜单程序设计,c语言课程设计报告-- 使用菜单选择趣味程序.doc

c语言课程设计报告-- 使用菜单选择趣味程序青岛农业大学课程设计报告题 目: 使用菜单选择趣味程序姓 名: 杨丽娜学 院: 理学与信息科学学院专 业: 通信工程班 级: 2班学 号:指导教师:年月日目 录…

各种服务常用端口号

常见的数据库,默认端口号是多少: 一、关系型数据库 1、MySql数据库 ,默认端口是: 3306; 2、Oracle数据库 ,默认端口号为:1521; 3、Sql Server数据库 ,默认端口号为:1433&#xff…

jboss配置ejb容器_JBoss AS 7 EJB3池配置

jboss配置ejb容器现在已经发布了AS 7.0.1,下面让我们看看有哪些新的EJB3功能可用。 就像我在上一篇文章中提到的那样 ,AS 7.0.1现在允许您为无状态会话bean和MDB配置池。 当前,我们允许在子系统级别配置池,这意味着该池将适用于服…

教你玩转CSS的所有字体,走过路过不要错过!!!

目录 CSS 字体 CSS字型 字体系列 字体样式 字体大小 设置字体大小像素 用em来设置字体大小

c语言单元二实验报告,C语言第七次实验报告

C程序设计实验报告姓名:林世龙 实验地点:学校 实验时间:2020.06.03实验项目8.31.指针基础及指针运算8.3.2.数据交换8.3.3.字符串反转及字符串连接8.3.4.数组元素奇偶排列一、实验目的与要求1、加强对学生对指针数据类型的理解,熟…

(剑指Offer)面试题4:替换空格

题目: 请实现一个函数,把字符串中的每个空格替换成“%20”,例如输入“We are happy”,则输出“We%20are%20happy”。 思路: 背景: 在网络编程中,如果URL参数中含有特殊字符,如空格,#…

Burpsuite爆破含CSRF-Token的程序

转载至https://www.se7ensec.cn/2018/10/21/Burpsuite%E7%88%86%E7%A0%B4%E5%90%ABCSRF-Token%E7%9A%84%E7%A8%8B%E5%BA%8F/ 3 年前发表 8 个月前更新 渗透测试 2 分钟读完 (大约273个字) 358次访问 Burpsuite爆破含CSRF-Token的程序 1. 抓包 0x01 开启burpsuite代理&#xff0…

Java Concurrency Essentials教程

课程大纲 并发一直是开发人员面临的挑战,编写并发程序可能非常困难。 引入并发性时,可能会发生很多事情,并且系统的复杂性会大大增加。 但是,编写健壮的并发程序的能力是开发人员的必备工具,并且可以帮助构建复杂的企…

如何玩转CSS链接(link)知识点?

CSS 链接 不同的链接可以有不同的样式。 链接样式 链接的样式,可以用任何CSS属性(如颜色,字体,背景等)。 特别的链接,可以有不同的样式,这取决于他们是什么状态。 这四个链接状态是: a:link - 正常,未访问过的链接a:visited - 用户已访问过的链接a:hover - 当用户…

IOS_月薪10k以上知识大总结

http://blog.csdn.net/sakulafly/article/details/40888143 转载于:https://www.cnblogs.com/luningning0901/p/4626749.html

adc0808的c语言编程51,51单片机驱动ADC0808电路图C51及汇编程序

这两天刚刚完成了一个用C编写的程序,这是我第一个用C语言编写的程序,并且调试成功。第一个C程序,值得纪念,也值得以后参考。本程序的功能是:1.ADC0808转换功能;2.数据16进制显示;3.串行通信数据…