本文将描述从在IBM JVM 1.6上运行的Weblogic 11g生产系统中观察到的最新Java死锁问题的完整根本原因分析。

此案例研究还将证明掌握线程转储分析技能的重要性; 包括用于IBM JVM Thread Dump格式。

环境规格

– Java EE服务器:Oracle Weblogic Server 11g和Spring 2.0.5 –操作系统:AIX 5.3 – Java虚拟机:IBM JRE 1.6.0 –平台类型:门户和订购应用程序
监控和故障排除工具
– JVM线程转储(IBM JVM格式)– Compuware Server Vantage(Weblogic JMX监视和警报)

问题概述

从Compuware Server Vantage观察到并报告了一个严重的线程阻塞问题,该问题影响了我们的2台Weblogic 11g生产托管服务器,从而导致了最终用户的应用程序影响和超时情况。

事实的收集和验证

像往常一样,Java EE问题调查需要收集技术和非技术事实,因此我们可以得出其他事实和/或就根本原因进行结论。 在采取纠正措施之前,要对以下事实进行核实,以便得出根本原因:
·对客户有什么影响? MEDIUM(16个中只有2个受管服务器/ JVM受影响)·受影响平台的最新更改? 是(新的与JMS相关的异步组件)·最近到受影响平台的流量有增加吗? 否·这个问题如何表现出来? 观察到线程突然增加,导致线程快速耗尽。·Weblogic托管服务器重新启动是否解决了问题? 是的,但是几个小时后问题又回来了(不可预测的间歇性模式)

结论1

该问题与间歇性卡住的线程行为有关,该行为当时仅影响少数Weblogic托管服务器

结论2

由于问题是断断续续的,因此不太可能出现全局根本原因,例如下游系统无响应

线程转储分析–第一遍

处理滞留的线程问题时,要做的第一件事是生成JVM线程转储。 无论您的环境规格和问题背景如何,这都是一条黄金法则。 JVM线程转储快照为您提供了有关活动线程及其当时正在执行的处理/任务类型的重要信息。
现在回到我们的案例研究,生成了一个IBM JVM线程转储(javacore.xyz格式),它确实揭示了以下Java线程死锁情况:

1LKDEADLOCK    Deadlock detected !!!NULL           ---------------------NULL           2LKDEADLOCKTHR  Thread '[STUCK] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)'' (0x000000012CC08B00)3LKDEADLOCKWTR    is waiting for:4LKDEADLOCKMON      sys_mon_t:0x0000000126171DF8 infl_mon_t: 0x0000000126171E38:4LKDEADLOCKOBJ      weblogic/jms/frontend/FESession@0x07000000198048C0/0x07000000198048D8: 3LKDEADLOCKOWN    which is owned by:2LKDEADLOCKTHR  Thread '[STUCK] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'' (0x000000012E560500)3LKDEADLOCKWTR    which is waiting for:4LKDEADLOCKMON      sys_mon_t:0x000000012884CD60 infl_mon_t: 0x000000012884CDA0:4LKDEADLOCKOBJ      weblogic/jms/frontend/FEConnection@0x0700000019822F08/0x0700000019822F20: 3LKDEADLOCKOWN    which is owned by:2LKDEADLOCKTHR  Thread '[STUCK] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)'' (0x000000012CC08B00)

死锁情况可以按照以下方式进行翻译:
– Weblogic线程8正在等待获取Weblogic线程10拥有的对象监视器锁
– Weblogic线程#10正在等待获取Weblogic线程#8拥有的对象监视器锁 结论: Weblogic线程#8和#10都在等待。 永远! 现在,在深入分析根本原因之前,让我为您提供有关Java Thread死锁的高级概述。

Java线程死锁概述

你们中的大多数人可能都熟悉Java Thread死锁原理,但是您真的遇到了真正的死锁问题吗?

根据我的经验,真正的Java死锁很少见,在过去的10年中,我只看到5次此类死锁。 原因是大多数与线程卡住有关的问题是由于线程挂起情况(正在等待远程IO调用等)引起的,而与其他线程没有真正的死锁条件有关。
Java线程死锁是一种情况,例如,线程A等待获取线程B持有的对象监视器锁,而该线程本身正等待获取线程A持有的对象监视器锁。这两个线程将永远彼此等待。 这种情况可以如下图所示:

线程死锁已确认……现在该怎么办?
一旦确认了死锁( 大多数JVM线程转储实现将为您突出显示 ),下一步就是通过检查死锁情况下涉及的每个线程及其当前任务和等待条件,来进行更深入的分析。
在我们的问题案例中,对于涉及死锁条件的每个线程,在部分线程堆栈跟踪下面找到: **请注意,出于保密目的,真实应用程序Java包名称已重命名**

Weblogic线程#8

'[STUCK] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)'' J9VMThread:0x000000012CC08B00, j9thread_t:0x00000001299E5100, java/lang/Thread:0x070000001D72EE00, state:B, prio=1(native thread ID:0x111200F, native priority:0x1, native policy:UNKNOWN)Java callstack:at weblogic/jms/frontend/FEConnection.stop(FEConnection.java:671(Compiled Code))at weblogic/jms/frontend/FEConnection.invoke(FEConnection.java:1685(Compiled Code))at weblogic/messaging/dispatcher/Request.wrappedFiniteStateMachine(Request.java:961(Compiled Code))at weblogic/messaging/dispatcher/DispatcherImpl.syncRequest(DispatcherImpl.java:184(Compiled Code))at weblogic/messaging/dispatcher/DispatcherImpl.dispatchSync(DispatcherImpl.java:212(Compiled Code))at weblogic/jms/dispatcher/DispatcherAdapter.dispatchSync(DispatcherAdapter.java:43(Compiled Code))at weblogic/jms/client/JMSConnection.stop(JMSConnection.java:863(Compiled Code))at weblogic/jms/client/WLConnectionImpl.stop(WLConnectionImpl.java:843)at org/springframework/jms/connection/SingleConnectionFactory.closeConnection(SingleConnectionFactory.java:342)at org/springframework/jms/connection/SingleConnectionFactory.resetConnection (SingleConnectionFactory.java:296)at org/app/JMSReceiver.receive()……………………………………………………………………

Weblogic线程#10

'[STUCK] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'' J9VMThread:0x000000012E560500, j9thread_t:0x000000012E35BCE0, java/lang/Thread:0x070000001ECA9200, state:B, prio=1(native thread ID:0x4FA027, native priority:0x1, native policy:UNKNOWN)Java callstack:at weblogic/jms/frontend/FEConnection .getPeerVersion(FEConnection.java:1381(Compiled Code))at weblogic/jms/frontend/FESession.setUpBackEndSession(FESession.java:755(Compiled Code))at weblogic/jms/frontend/FESession.consumerCreate(FESession.java:1025(Compiled Code))at weblogic/jms/frontend/FESession.invoke(FESession.java:2995(Compiled Code))at weblogic/messaging/dispatcher/Request.wrappedFiniteStateMachine(Request.java:961(Compiled Code))at weblogic/messaging/dispatcher/DispatcherImpl.syncRequest(DispatcherImpl.java:184(Compiled Code))at weblogic/messaging/dispatcher/DispatcherImpl.dispatchSync(DispatcherImpl.java:212(Compiled Code))at weblogic/jms/dispatcher/DispatcherAdapter.dispatchSync(DispatcherAdapter.java:43(Compiled Code))at weblogic/jms/client/JMSSession.consumerCreate(JMSSession.java:2982(Compiled Code))at weblogic/jms/client/JMSSession.setupConsumer(JMSSession.java:2749(Compiled Code))at weblogic/jms/client/JMSSession.createConsumer(JMSSession.java:2691(Compiled Code))at weblogic/jms/client/JMSSession.createReceiver(JMSSession.java:2596(Compiled Code))at weblogic/jms/client/WLSessionImpl.createReceiver(WLSessionImpl.java:991(Compiled Code))at org/springframework/jms/core/JmsTemplate102.createConsumer(JmsTemplate102.java:204(Compiled Code))at org/springframework/jms/core/JmsTemplate.doReceive(JmsTemplate.java:676(Compiled Code))at org/springframework/jms/core/JmsTemplate$10.doInJms(JmsTemplate.java:652(Compiled Code))at org/springframework/jms/core/JmsTemplate.execute(JmsTemplate.java:412(Compiled Code))at org/springframework/jms/core/JmsTemplate.receiveSelected(JmsTemplate.java:650(Compiled Code))at org/springframework/jms/core/JmsTemplate.receiveSelected(JmsTemplate.java:641(Compiled Code))at org/app/JMSReceiver.receive()……………………………………………………………

如您在上面的“线程跟踪跟踪”中所看到的,这种死锁确实来自我们的应用程序代码,该应用程序代码使用Spring框架API进行JMS使用者实现(在不使用MDB的情况下非常有用)。 堆栈跟踪非常有趣,它揭示了两个线程都在与相同的 Weblogic JMS使用者会话/连接竞争的情况下,并导致死锁情况:
– Weblogic线程#8试图重置关闭当前的JMS连接– Weblogic线程#10试图使用相同的JMS连接/会话以创建新的JMS使用方–触发了线程死锁!

根本原因:非线程安全的Spring JMS SingleConnectionFactory实现

Spring JIRA错误数据库的代码回顾和快速研究确实揭示了以下与上述分析完美相关的以下线程安全缺陷:
#SingleConnectionFactory的resetConnection导致与基础OracleAQ的JMS连接的死锁https://jira.springsource.org/browse/SPR-5987
Spring SingleConnectionFactory的修补程序于2009年发布,确实涉及添加适当的sync {}块,以防止在发生JMS Connection重置操作时线程死锁:

synchronized (connectionMonitor) {//if condition added to avoid possible deadlocks when trying to reset the target connection if (!started) {this.target.start(); started = true; }}

我们的团队目前正计划将该Spring补丁不久后集成到我们的生产环境中。 在我们的测试环境中执行的初始测试是肯定的。

结论

我希望这个案例研究能帮助您理解现实中的Java线程死锁问题,以及适当的线程转储分析技能如何使您能够在代码级快速查明与线程相关的卡住问题的根本原因。 请不要犹豫,发表任何评论或问题。

参考: Java Thread死锁–来自我们的JCG合作伙伴 Pierre-Hugues Charbonneau的案例研究 ,位于Java EE支持模式和Java教程博客上。

翻译自: https://www.javacodegeeks.com/2012/06/java-thread-deadlock-case-study.html

Java线程死锁–案例研究相关推荐

  1. java线程死锁_Java线程死锁–案例研究

    java线程死锁 本文将描述从在IBM JVM 1.6上运行的Weblogic 11g生产系统中观察到的最新Java死锁问题的完整根本原因分析. 此案例研究还将证明掌握线程转储分析技能的重要性: 包括 ...

  2. Log4j线程死锁–案例研究

    此案例研究描述了影响Weblogic Portal 10.0生产环境的Apache Log4j线程争用问题的完整根本原因分析和解决方案. 它还将说明在开发和支持Java EE应用程序时适当的Java类 ...

  3. java线程死锁_Java并发:隐藏线程死锁

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

  4. java线程池案例_使用Executors 和 ThreadPoolExecutor实现Java线程池案例

    并发主题 使用Executors 和 ThreadPoolExecutor实现Java线程池案例 首先需要一个工作线程: package com.journaldev.threadpool; publ ...

  5. oracle线程阻塞_Oracle Service Bus –线程阻塞案例研究

    oracle线程阻塞 本案例研究描述了在AIX 6.1和IBM Java VM 1.6上运行的Oracle Service Bus 11g遇到的线程阻塞问题的完整根本原因分析过程. 本文也是您提高线程 ...

  6. Oracle Service Bus –线程阻塞案例研究

    本案例研究描述了在AIX 6.1和IBM Java VM 1.6上运行的Oracle Service Bus 11g遇到的线程阻塞问题的完整根本原因分析过程. 本文也是您提高线程转储分析技能的绝佳机会 ...

  7. linux查看java线程死锁_ccriticalsection 多线程 死锁_c++ 线程死锁_linux 线程 死锁

    qq_407283393122018-12-10 一个很蠢的造成死锁的问题 wanglt3113172018-12-12 什么是死锁,死锁的原因,如何避免 apanying902019-01-09 c ...

  8. java 线程死锁简单例子_java 多线程死锁详解及简单实例

    java 多线程死锁 相信有过多线程编程经验的朋友,都吃过死锁的苦.除非你不使用多线程,否则死锁的可能性会一直存在.为什么会出现死锁呢?我想原因主要有下面几个方面: (1)个人使用锁的经验差异 (2) ...

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

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

最新文章

  1. 立体显示与BCN双稳态手性向列相
  2. 【二级java】操作题知识点积累
  3. php数组循环便利,浅析PHP中for与foreach两个循环结构遍历数组的区别
  4. 关于JAP FetchType.LAZY(hibernate实现)的理解
  5. qt 调用qpainter_在Qt5.4中如何实现QOpenGLWidget和QPainter混合编程
  6. [bzoj4994][Usaco2017 Feb]Why Did the Cow Cross the Road III_树状数组
  7. perl数组硬引用_Perl 继续前行,Perl 7 将是下一代(硬核老王点评版)
  8. caffe to pytorch
  9. 韭菜翻盘致富!加拿大学者发布比特币的价格预测模型
  10. Eclipse如何新建TOMCAT并配置Server Locations和Publishing属性
  11. Oracle操作(转)
  12. android窗口动画和壁纸关系,Android壁纸管理(Android N)
  13. mysql 数据库修改ip_mysql数据库学习之修改主库ip地址
  14. U-BLOX GPS 模块及GPRMC指令解析
  15. 如何用Matlab求不定积分
  16. h5-吸顶效果的实现方法
  17. php 英文小写转大写数字,php 英文字符大小写转换函数
  18. FME中的栅格数据操作之一——转换器小结
  19. MacBook进水记
  20. 交易系统开发(十一)——QuickFIX简介

热门文章

  1. idea部署maven+javaweb项目到jboss
  2. 转:权限管理——用户认证和用户授权
  3. java名 java_Java Syncrhonisers
  4. 将Visual Studio Code设置为jshell中的默认编辑器
  5. jetty嵌入式容器_嵌入式Jetty和Apache CXF:借助Spring Security来保护REST服务
  6. 如何在Java中将数组转换为列表
  7. Apache Camel 3.1 –更多骆驼核心优化(第2部分)
  8. 使用Caffeine和Spring Boot的多个缓存配置
  9. jpa中::::_项目学生:JPA标准查询
  10. java 面试指南_Java面试参考指南–第1部分