Java并发:隐藏线程死锁

大多数Java程序员熟悉Java线程死锁概念。 它本质上涉及2个线程,它们彼此永远等待。 这种情况通常是平面(同步)或ReentrantLock(读或写)锁排序问题的结果。

Found one Java-level deadlock:
=============================
"pool-1-thread-2":waiting to lock monitor 0x0237ada4 (object 0x272200e8, a java.lang.Object),which is held by "pool-1-thread-1"
"pool-1-thread-1":waiting to lock monitor 0x0237aa64 (object 0x272200f0, a java.lang.Object),which is held by "pool-1-thread-2"

好消息是,HotSpot JVM始终可以为您检测到这种情况……还是吗? 最近一个影响Oracle Service Bus生产环境的线程死锁问题迫使我们重新审视此经典问题并确定是否存在“隐藏”死锁情况。 本文将通过一个简单的Java程序演示并复制非常特殊的锁排序死锁条件,最新的HotSpot JVM 1.7并未检测到该情况。 您还可以在本文结尾处找到一个视频 ,向您介绍Java示例程序和所使用的故障排除方法。

犯罪现场

我通常喜欢将主要的Java并发问题与犯罪现场进行比较,在犯罪现场您扮演首席调查员的角色。 在这种情况下,“犯罪”是客户IT环境的实际生产中断。 您的工作是:

  • 收集所有证据,提示和事实(线程转储,日志,业务影响,负载数字…)
  • 询问证人和领域专家(支持团队,交付团队,供应商,客户……)

调查的下一步是分析收集的信息,并建立一个或多个“可疑”的潜在清单以及清晰的证据。 最终,您希望将其范围缩小到主要可疑或根本原因。 显然,“直到证明有罪之前无罪”的法律在这里并不适用,恰恰相反。 缺乏证据可能会阻止您实现上述目标。 接下来,您将看到Hotspot JVM缺少死锁检测并没有必要证明您没有在处理此问题。

犯罪嫌疑人

在此故障排除上下文中,“可疑”定义为具有以下有问题的执行模式的应用程序或中间件代码。

  • 使用FLAT锁,然后使用ReentrantLock WRITE锁(执行路径#1)
  • 使用ReentrantLock READ锁,然后使用FLAT锁(执行路径#2)
  • 由2个Java线程并发执行,但执行顺序相反

上面的锁排序死锁标准可以如下所示:

现在,让我们通过示例Java程序来复制此问题,并查看JVM线程转储输出。

示例Java程序

上面的死锁条件是首先从我们的Oracle OSB问题案例中发现的。 然后,我们通过一个简单的Java程序重新创建了它。 您可以在此处 下载我们程序的完整源代码。 该程序只是创建并触发2个工作线程。 它们每个执行不同的执行路径,并尝试以不同的顺序获取共享对象上的锁。 我们还创建了一个死锁检测器线程以进行监视和记录。 现在,在下面找到实现2条不同执行路径的Java类。

package org.ph.javaee.training8;import java.util.concurrent.locks.ReentrantReadWriteLock;/*** A simple thread task representation* @author Pierre-Hugues Charbonneau**/
public class Task {// Object used for FLAT lockprivate final Object sharedObject = new Object();// ReentrantReadWriteLock used for WRITE & READ locksprivate final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();/***  Execution pattern #1*/public void executeTask1() {// 1. Attempt to acquire a ReentrantReadWriteLock READ locklock.readLock().lock();// Wait 2 seconds to simulate some work...try { Thread.sleep(2000);}catch (Throwable any) {}try {              // 2. Attempt to acquire a Flat lock...synchronized (sharedObject) {}}// Remove the READ lockfinally {lock.readLock().unlock();}           System.out.println("executeTask1() :: Work Done!");}/***  Execution pattern #2*/public void executeTask2() {// 1. Attempt to acquire a Flat locksynchronized (sharedObject) {                 // Wait 2 seconds to simulate some work...try { Thread.sleep(2000);}catch (Throwable any) {}// 2. Attempt to acquire a WRITE lock                   lock.writeLock().lock();try {// Do nothing}// Remove the WRITE lockfinally {lock.writeLock().unlock();}}System.out.println("executeTask2() :: Work Done!");}public ReentrantReadWriteLock getReentrantReadWriteLock() {return lock;}
}

一旦触发死锁情况,就会使用JVisualVM生成JVM线程转储。

从Java线程转储示例中可以看到。 JVM未检测到此死锁条件(例如,不存在“发现一个Java级死锁”),但很明显,这两个线程处于死锁状态。

根本原因:ReetrantLock READ锁定行为

至此,我们发现的主要解释与ReetrantLock READ锁的用法有关。 读锁通常不设计为具有所有权概念。 由于没有哪个线程持有读取锁的记录,因此这似乎可以防止HotSpot JVM死锁检测器逻辑检测到涉及读锁的死锁。 从那时起,我们进行了一些改进,但是我们可以看到JVM仍然无法检测到这种特殊的死锁情况。 现在,如果我们用写锁替换程序中的读锁(执行模式2),那么JVM将最终检测到死锁情况,但是为什么呢?

Found one Java-level deadlock:
=============================
"pool-1-thread-2":waiting for ownable synchronizer 0x272239c0, (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync),which is held by "pool-1-thread-1"
"pool-1-thread-1":waiting to lock monitor 0x025cad3c (object 0x272236d0, a java.lang.Object),which is held by "pool-1-thread-2"Java stack information for the threads listed above:
===================================================
"pool-1-thread-2":at sun.misc.Unsafe.park(Native Method)- parking to wait for  <0x272239c0> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)at java.util.concurrent.locks.AbstractQueuedSynchronizer.
parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)at java.util.concurrent.locks.AbstractQueuedSynchronizer.
acquireQueued(AbstractQueuedSynchronizer.java:867)at java.util.concurrent.locks.AbstractQueuedSynchronizer.
acquire(AbstractQueuedSynchronizer.java:1197)at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:945)at org.ph.javaee.training8.Task.executeTask2(Task.java:54)- locked <0x272236d0> (a java.lang.Object)at org.ph.javaee.training8.WorkerThread2.run(WorkerThread2.java:29)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)at java.lang.Thread.run(Thread.java:722)
"pool-1-thread-1":at org.ph.javaee.training8.Task.executeTask1(Task.java:31)- waiting to lock <0x272236d0> (a java.lang.Object)at org.ph.javaee.training8.WorkerThread1.run(WorkerThread1.java:29)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)at java.lang.Thread.run(Thread.java:722)

这是因为类似于平面锁,JVM跟踪写入锁。 这意味着HotSpot JVM死锁检测器似乎当前被设计用来检测:

  • 对象监视器上涉及FLAT锁的死锁
  • 死锁涉及与WRITE锁相关联的已锁定拥有的同步器

缺少读取锁每线程跟踪似乎可以防止这种情况下的死锁检测,并大大增加了故障排除的复杂性。 我建议您阅读Doug Lea在整个问题上的评论 ,因为早在2005年就开始担心由于某些潜在的锁定开销而可能添加每线程读取保持跟踪。 如果您怀疑涉及读取锁的隐藏死锁情况,请在下面的故障排除建议中查找:

  • 仔细分析线程调用堆栈跟踪,它可能会揭示某些代码潜在地获取读锁,并阻止其他线程获取写锁。
  • 如果您是代码的所有者,请通过使用lock.getReadLockCount()方法来跟踪读取锁的计数。

我期待着您的反馈,特别是对于具有此类涉及读锁的死锁经验的个人。 最后,在下面的视频中找到通过示例Java程序的执行和监视来解释这些发现的视频。


参考: Java并发性: Java EE支持模式和Java教程博客中,我们的JCG合作伙伴 Pierre-Hugues Charbonneau 隐藏的线程死锁 。

翻译自: https://www.javacodegeeks.com/2013/02/java-concurrency-the-hidden-thread-deadlocks.html

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

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

相关文章

vue中使用axios发送请求

我们知道&#xff0c;vue2.0以后&#xff0c;vue就不再对vue-resource进行更新&#xff0c;而是推荐axios&#xff0c;而大型项目都会使用 Vuex 来管理数据&#xff0c;所以这篇博客将结合两者来发送请求 1.安装axios cnpm i axios -S 2.方案一&#xff1a;修改原型链 首先&…

django缓存

由于Django是动态网站&#xff0c;所有每次请求均会去数据进行相应的操作&#xff0c;当程序访问量大时&#xff0c;耗时必然会更加明显&#xff0c;最简单解决方式是使用&#xff1a;缓存&#xff0c;缓存将一个某个views的返回值保存至内存或者memcache中&#xff0c;5分钟内…

linux 输入法成繁体字_寻找Ubuntu中繁体字输入法

当客户来自港台地区时&#xff0c;英文和繁体字就成了交流的主要工具。windows下我们有搜狗输入法可以切换简体与繁体&#xff0c;那么Ubuntu下怎么办&#xff1f;這是我第一次考慮這個問題&#xff0c;在我的印象裏Linux下的中文輸入法還不是那麼完善&#xff0c;所以我進行了…

vue跨域解决方法

vue跨域解决方法 vue项目中&#xff0c;前端与后台进行数据请求或者提交的时候&#xff0c;如果后台没有设置跨域&#xff0c;前端本地调试代码的时候就会报“No Access-Control-Allow-Origin header is present on the requested resource.” 这种跨域错误。 要想本地正常的调…

Spring 3.2的REST异常处理

1.概述 本文将重点介绍如何使用REST API的Spring实现异常处理 。 我们将介绍在Spring 3.2之前可用的较旧的解决方案&#xff0c;然后是对Spring 3.2的新支持。 本文的主要目的是展示如何最好地将应用程序中的异常映射到HTTP状态代码。 哪种状态代码不适合本文中的哪种情况&…

kali中常用的ctf工具

exiftool:查看图片的exif信息。 pngcheck:修复被破坏的png图片 pngtools:深入研究png文件的数据 steganographic&#xff1a;用来提取图片中的隐藏信息 stegsolve.jar:kali中没有该工具&#xff0c;但是可以自己下 gimp:提供了转换各类图像文件可视化数据的功能&#xff0c;还可…

linux将所有文件生成lst_Linux自定义repo文件

repo文件简介repo文件是CentOS中yum源(软件仓库)的配置文件&#xff0c;通常一个repo文件定义了一个或者多个软件仓库的细节内容&#xff0c;例如我们将从哪里下载需要安装或者升级的软件包&#xff0c;repo文件中的设置内容将被yum读取和应用yum原理YUM的工作原理并不复杂&…

使用JUnit规则测试预期的异常

这篇文章展示了如何使用JUnit测试预期的异常。 让我们从我们要测试的以下类开始&#xff1a; public class Person {private final String name;private final int age;/*** Creates a person with the specified name and age.** param name the name* param age the age* th…

CSS盒子模型之详解

前言&#xff1a; 盒子模型是css中最核心的基础知识&#xff0c;理解了这个重要的概念才能更好的排版&#xff0c;进行页面布局。一、css盒子模型概念 CSS盒子模型 又称框模型 (Box Model) &#xff0c;包含了元素内容&#xff08;content&#xff09;、内边距&#…

LeetCode的二分查找的练习部分总结

这两天由于工作的原因&#xff0c;一直没有写博客&#xff0c;但是却把LeetCode上面的题目做了不少——二分查找。上面这些题都是这两天写的。现在简单做一个总结。 首先二分查找的思想就是对一个有规律的元素&#xff08;事情&#xff09;进行不断的排除&#xff0c;最后找到符…

在Mac上安装IntelliJ IDEA

在Mac上安装IntelliJ IDEA http://www.jetbrains.com/idea/documentation/ 入门视频 这篇文章旨在介绍如何在Mac系统上安装IntelliJ IDEA&#xff0c;至于IntelliJ IDEA的介绍和使用方法&#xff0c;大家另行查阅&#xff0c;本篇的文章不再详细阐述。 简短解说&#xff0c;I…

mysql sohu_【MySQL中间件之SOHU-DBProxy】

SOHU-DBProxy是由 搜狐 数据库团队开发维护的一个基于MySQL协议的数据中间层项目。它在MySQL官方推出的MySQL-Proxy 0.8.3版本的基础上&#xff0c; 修改了大量bug&#xff0c;添加了很多功能特性。现在已经在sohu的多个业务线上使用DBProxy 兼容 MySQL 协议&#xff0c;可以用…

JavaFX:太空侵略者在175 LOC以下

使用当前版本的API&#xff0c;我对太空侵略者的评价不到175个LOC。 我的API中有很多“功能接口”&#xff0c;可以使用JavaFX 8&#xff08;例如SpriteProvider和CollisionHandler&#xff09;将其转换为Lambda表达式。 这将使代码更好&#xff0c;更短。 我可能还可以通过捆绑…

行内元素,块级元素,各自特点及其相互转化

作为一名小前端&#xff0c;块级元素、行内元素用了几千几万次&#xff0c;除了“块级独占一行&#xff0c;行内不独占”之外&#xff0c;对细节属性的了解十分匮乏&#xff0c;今天做以部分属性的测试和阐述。 一、 对物理属性的支持 元素类别widthheightpaddingmargin是否独…

mysql断开同步并记录位置_数据库同步自动断开问题的处理

堡垒机的实施过程中&#xff0c;因为做了双机&#xff0c;所以要对两台堡垒机进行数据库的主从同步和HA配置。在部署完mysql主从同步以后&#xff0c;发现同步会有中断的现象。中断表现为Slave_IO_Running: YesSlave_SQL_Running: NoReplicate_Do_DB:Replicate_Ignore_DB:Repli…

[NOIP2016提高组]换教室

题目&#xff1a;洛谷P1850、UOJ#262、BZOJ4720、Vijos P2005。 题目大意&#xff1a;有n个时间段&#xff0c;第i个时间段只能在教室$c_i$上课&#xff0c;另一个上这门课的教室在$d_i$。现在你最多可以进行m次申请&#xff0c;对于第i个时间段的申请如果成功&#xff0c;那么…

从RSS Feed和YQL创建数据表

Yahoo Query Language&#xff08; YQL &#xff09;是一种查询语言&#xff0c;例如SQL。 使用YQL&#xff0c;我们可以跨Web服务 查询 &#xff0c; 过滤和联接数据。 YQL也可以阅读RSS feed。 响应可以是JSON或XML。 雅虎提供了一个YQL控制台&#xff0c;用于调试 &…

background-image使用svg如何改变颜色

结论 在我多番测试之后&#xff0c;才发现background-image使用svg&#xff0c;改变颜色根本做不了。 分析 当svg图片被使用成background-image&#xff0c;颜色的设置需要在svg内部才能生效。在外部CSS设置颜色样式&#xff0c;却是无效&#xff0c;这其实可以从CSS选择器得到…

NOIP 2012 Day2

tags: 扩展欧几里得二分答案查分倍增二分答案贪心NOIP categories:信息学竞赛总结同余方程借教室疫情控制 同余方程 Solution 首先同余式可以转化为等式.\[ax\equiv 1\mod b\Leftrightarrow axby1\]   根据扩展欧几里得定理, 对于式\[axbyk(a,b),k\in \mathbf{R}\]一定存在整…

Qt之QSS(Q_PROPERTY-自定义属性)

版权声明&#xff1a;进步始于交流&#xff0c;收获源于分享&#xff01;纯正开源之美&#xff0c;有趣、好玩、靠谱。。。作者&#xff1a;一去丶二三里 博客地址&#xff1a;http://blog.csdn.net/liang19890820 目录(?)[] 简述 在Qt之QSS&#xff08;Q_PROPERTY-原始属性&a…