本文概览:在程序hang住时,可以通过jstack获取线程堆栈信息,分析是否是死锁或者死循环导致程序hang住。发现是log4j的问题,通过修改<root>中日志级别由DEBUG变为INFO和注释掉ConsoleAppender来修复

1 问题描述

在执行任务时,hang住了,于是通过 jstack  -l  进程ID命令来获取线程堆栈信息。如下:

2 线程dump文件的介绍

2.1 进程状态

首先对于上面dump文件中线程的状态进行解析解释。java的进程状态有如下:

对于每一个状态解释:

  • RUNNABLE  正在执行的线程
  • BLOCKED   RetrentLock#lock 或者 Synchronized 函数阻塞
  • WAITING     通过wait操作或ReentrantLock#Condition进行阻塞。
  • TIMED_WAITING  就是在wiat或者ReentrantLock#Condition进行阻塞时,设置了一个阈值时间。

不同线程状态之间转换可以通过下图来展示(http://www.uml-diagrams.org/examples/java-6-thread-state-machine-diagram-example.html

55341366

2.2 死锁状态分析

1 、如果怀疑是死锁,需要关注线程什么状态?

首先想到的是要查看下Block状态的线程。对于死锁产生的一个例子如下

还有一种情况是,线程thread1获取了一个锁,然后进行死循环,造成等待这个锁的thread2thread3进入了hang住的状态。

除了BLOCKED状态,对于WAITING状态,相当于使用了wait操作或者在RettrentLockCondition,也会造成死锁。

2、获取产生死锁的线程

通过分析 “locked xxx “ “waiting to lock  xxx”信息来进行分析。

1)取得 BLOCKED 状态的线程,

在这些线程中通过 “wait  to lock  xxx ”来找到锁的关键字,如下得到关键字0x00000000b84256e0

2)查询“locked 0x00000000b84256e0”的线程

3)这样,我们就可以知道 线程“fileModelCheckExecutor-18” 获取了锁 “0x00000000b84256e0”,其他线程都在等着获取这个锁而被阻塞。但是“fileModelCheckExecutor-18” 这个线程进行入了死循环。

注意:为什么说是死循环?因为这个线程状态为Runnable。如果改线程状态为Blocked,那么此时就是死锁状态了。

3 分析 dump文件

1、首先找到处于blocked状态线程,根据“waiting to lock <0x00000000b84256e0>   “找到关键词“0x00000000b84256e0”

2、整个文件中搜索  “0x00000000b84256e0” ,发现有一个地方进行locked,对 “0x00000000b84256e0” 进行了上锁。然后其他等待这个锁的地方都被阻塞了看,如下:

2、定位

就是log4j造成的,如上日志中 线程”fileModelCheckExecutor-18″ 进入到了死循环。

3、解决

如下是从网上找的的方案:将root的log级别设置为INFO.

https://stackoverflow.com/questions/3537870/production-settings-file-for-log4j/

4、后续(补)

当前文件中,出现问题的线程信息如下

又查看了2017-05-26和2017-05-24的dump文件,如下:

  • 2017-05-26的dump文件

  • 2017-05-24的dump文件

由上面三个信息,共同点都涉及到了ConsoleAppender、CosoleHandler。所以这里想到一个方法是注释掉consoleAppender,如下

参考资料

1、线程状态  http://fangjian0423.github.io/2016/06/04/java-thread-state/xi

2、jstack分析线程堆栈   https://segmentfault.com/a/1190000000615690

(全文完)

 

分类&标签

发表评论

电子邮件地址不会被公开。 必填项已用*标注