jstack Dump日志文件中的线程状态

jstack
Dump 日志文件中的线程状态

dump 文件里,值得关注的线程状态有:

  1. 死锁,Deadlock(重点关注) 

  2. 执行中,Runnable

  3. 等待资源,Waiting on condition(重点关注)

  4. 等待获取监视器,Waiting on monitor
    entry(重点关注)

  5. 暂停,Suspended

  6. 对象等待中,Object.wait() 或 TIMED_WAITING

  7. 阻塞,Blocked(重点关注)  

  8. 停止,Parked

下面我们先从第一个例子开始分析,然后再列出不同线程状态的含义以及注意事项,最后再补充两个实例。

综合示范一:Waiting
to lock 和 Blocked

实例如下:

"RMI
TCP Connection(267865)-172.16.5.25" daemon prio=10 tid=0x00007fd508371000
nid=0x55ae waiting for monitor entry [0x00007fd4f8684000]

java.lang.Thread.State: BLOCKED (on object
monitor)

at
org.apache.log4j.Category.callAppenders(Category.java:201)

waiting to lock
<0x00000000acf4d0c0>
 (a
org.apache.log4j.Logger)

at
org.apache.log4j.Category.forcedLog(Category.java:388)

at
org.apache.log4j.Category.log(Category.java:853)

at
org.apache.commons.logging.impl.Log4JLogger.warn(Log4JLogger.java:234)

at
com.tuan.core.common.lang.cache.remote.SpyMemcachedClient.get(SpyMemcachedClient.java:110)

……

1)线程状态是 Blocked,阻塞状态。说明线程等待资源超时!

2)“ waiting to lock
<0x00000000acf4d0c0>”指,线程在等待给这个 0x00000000acf4d0c0
地址上锁(英文可描述为:trying to
obtain  0x00000000acf4d0c0 lock)。

3)在 dump 日志里查找字符串 0x00000000acf4d0c0,发现有大量线程都在等待给这个地址上锁。如果能在日志里找到谁获得了这个锁(如locked
< 0x00000000acf4d0c0 >),就可以顺藤摸瓜了。

4)“waiting for monitor
entry
”说明此线程通过 synchronized(obj) {……} 申请进入了临界区,从而进入了下图1中的“Entry
Set”队列,但该 obj 对应的 monitor 被其他线程拥有,所以本线程在 Entry Set 队列中等待。

5)第一行里,"RMI TCP
Connection(267865)-172.16.5.25"是 Thread Name 。tid指Java Thread
id。nid指native线程的id。prio是线程优先级。[0x00007fd4f8684000]是线程栈起始地址。

Dump文件中的线程状态含义及注意事项

含义如下所示:

  • Deadlock:死锁线程,一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。

  • Runnable:一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换。

  • Waiting on condition:等待资源,或等待某个条件的发生。具体原因需结合
    stacktrace来分析。Blocked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。
    • 如果堆栈信息明确是应用代码,则证明该线程正在等待资源。一般是大量读取某资源,且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取。

    • 又或者,正在等待其他线程的执行等。

    • 如果发现有大量的线程都在处在 Wait on
      condition,从线程 stack看,正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。
      • 一种情况是网络非常忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;

      • 另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。

    • 另外一种出现 Wait on
      condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
  • Waiting for monitor entry 和 in
    Object.wait():Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者
    Class的锁。每一个对象都有,也仅有一个 monitor。从下图1中可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是
    “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait
    Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitor entry”,而在 “Wait
    Set”中等待的线程状态是 “in Object.wait()”。

图1
A Java Monitor

综合示范二:Waiting
on condition
 和 TIMED_WAITING

实例如下:

"RMI
TCP Connection(idle)" daemon prio=10 tid=0x00007fd50834e800 nid=0x56b2 waiting
on condition
 [0x00007fd4f1a59000]

java.lang.Thread.State: TIMED_WAITING
(parking)

at
sun.misc.Unsafe.park(Native Method)

parking
to wait for  <0x00000000acd84de8>
 (a
java.util.concurrent.SynchronousQueue$TransferStack)

at
java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)

at
java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)

at
java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)

at
java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)

at
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)

at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)

at
java.lang.Thread.run(Thread.java:662)

1)“TIMED_WAITING (parking)”中的
timed_waiting 指等待状态,但这里指定了时间,到达指定的时间后自动退出等待状态;parking指线程处于挂起中。

2)“waiting on
condition
”需要与堆栈中的“parking
to wait for  <0x00000000acd84de8>
 (a
java.util.concurrent.SynchronousQueue$TransferStack)”结合来看。首先,本线程肯定是在等待某个条件的发生,来把自己唤醒。其次,SynchronousQueue
并不是一个队列,只是线程之间移交信息的机制,当我们把一个元素放入到 SynchronousQueue
中时必须有另一个线程正在等待接受移交的任务,因此这就是本线程在等待的条件。

3)别的就看不出来了。

综合示范三:in
Obejct.wait()
 和 TIMED_WAITING

实例如下:

"RMI
RenewClean-[172.16.5.19:28475]"
daemon prio=10 tid=0x0000000041428800 nid=0xb09 in Object.wait() [0x00007f34f4bd0000]

java.lang.Thread.State: TIMED_WAITING
(on object monitor)

at
java.lang.Object.wait(Native Method)

waiting
on <0x00000000aa672478> (a
java.lang.ref.ReferenceQueue$Lock)

at
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)

locked
<0x00000000aa672478> (a
java.lang.ref.ReferenceQueue$Lock)

at
sun.rmi.transport.DGCClient$EndpointEntry$RenewCleanThread.run(DGCClient.java:516)

at
java.lang.Thread.run(Thread.java:662)

1)“TIMED_WAITING (on object
monitor)
”,对于本例而言,是因为本线程调用了 java.lang.Object.wait(long timeout)
而进入等待状态。

2)“Wait Set”中等待的线程状态就是“ in Object.wait() ”。当线程获得了
Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(一般就是被 synchronized 的对象)的 wait() 方法,放弃了
Monitor,进入 “Wait Set”队列。只有当别的线程在该对象上调用了 notify() 或者 notifyAll() ,“ Wait
Set”队列中线程才得到机会去竞争,但是只有一个线程获得对象的 Monitor,恢复到运行态。

3)RMI RenewClean 是 DGCClient 的一部分。DGC 指的是
Distributed GC,即分布式垃圾回收。

4)请注意,是先 locked
<0x00000000aa672478>
,后 waiting
on <0x00000000aa672478>
,之所以先锁再等同一个对象,请看下面它的代码实现:

static private class  Lock { };

private Lock lock = new Lock();

public Reference<? extends T> remove(long
timeout)

{

synchronized (lock) {

Reference<? extends T> r = reallyPoll();

if (r != null) return r;

for (;;) {

lock.wait(timeout);

r = reallyPoll();

……

}

}

即,线程的执行中,先用 synchronized 获得了这个对象的
Monitor(对应于  locked
<0x00000000aa672478>
 );当执行到 lock.wait(timeout);,线程就放弃了
Monitor 的所有权,进入“Wait Set”队列(对应于  waiting
on <0x00000000aa672478>
 )。

5)从堆栈信息看,是正在清理 remote references to remote objects
,引用的租约到了,分布式垃圾回收在逐一清理呢。

参考资源:

1)CUBRID,2012,How
to Analyze Java Thread Dumps

2)iteye,2012,虚拟机stack全分析

3)iteye,2008,如何分析Java虚拟机死锁

4)csdn,2012,java
stack dump中JVM运行过程中产生的一些常见线程介绍和解释

5)2009,Java线程dump的分析

6)jiacheo,2012,tomcat
thread dump 分析

spymemcached 相关文章:

1)spymemcached
的 useNagle 问题与 TCP/IP延迟发送数据

2)spymemcached
:某个mc节点操作连续超时超过998次就 Auto-Reconnect 的特性

3)关于
Multiget hole:spymemcached对此的实现方法

1)55最佳实践系列:MongoDB最佳实践 (2012-12-15 15:48) 2)55最佳实践系列:Logging最佳实践 (2012-12-15
16:43)

3)最佳实践系列:前端代码标准和最佳实践 (2012-12-19
23:33)

jstack Dump日志文件中的线程状态

时间: 2024-08-03 10:27:39

jstack Dump日志文件中的线程状态的相关文章

将PHP错误输入到日志文件中

(LAMP)禁止客户端浏览器显示PHP代码错误,将错误信息保存到日志文件中:在php配置文件中找到php.ini(如在Centos6.7下的/etc/php.ini中),设置 display_errors = Off //不允许在浏览器中显示错误信息 log_errors = On //将错误信息输入到log文件中 error_log = /var/www/html/php_errors_log//指定错误日志位置找到apache的配置文件http.conf(如在Centos6.7下的/etc/

Java中的线程状态转换和线程控制常用方法

Java 中的线程状态转换: [注]:不是 start 之后就立刻开始执行, 只是就绪了(CPU 可能正在运行其他的线程). [注]:只有被 CPU 调度之后,线程才开始执行, 当 CPU 分配给你的时间片到了, 又回到就绪状态, 继续排队等候. 线程控制的基本方法: isAlive(): 判断线程是否还活着, start 之后,终止之前都是活的; getPriority(): 获得线程的优先级数值; setPriority(): 设置线程的优先级数值(线程室友优先级别的);   Thread.

log4j:特定类的日志输出到指定的日志文件中

问题描述:我有一个类foo.bar.Baz,我想让Baz这个类的日志输出到指定的日志文件中,其它的就使用默认的配置. log4j.rootLogger=ERROR, logfile log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender log4j.appender.logfile.datePattern='-'dd'.log' log4j.appender.logfile.File=log/radius-prod.log

删除大日志文件中的某段数据

using System; using System.IO; using System.Linq; using System.Text; namespace TestMultyConsole2 { public class LocalFileHelper { /// <summary> /// 删除大日志文件中的某些数据 /// </summary> /// <param name="filePath">源文件路径</param> ///

当日志文件中的时间与主机时间不同步时,怎么监控每隔五分钟检测一次日志文件是否出自按某个关键字?

今有需求:需要监控每隔五分钟检测一次日志文件是否出自按某个关键字.利用过滤全部的日志信息 虽然可以过滤出来关键字告警,但是修复后,依然还是会报警,存在局限性,所以需要使用以下办法来实现需求. 本想循环获取5分钟内的时间戳,然后从日志文件中grep这个时间端的信息,然后再获取关键字,但是通过查看日志文件发现时间戳与主机时间不同步,所以,这种方法不可取.那么怎么获取最近五分钟的日志信息,再过滤关键字呢?思索了很久,又有了新思路.将现在的文件日志重定向到一个新的文件里面 cat /var/log/xx

学习java线程状态和看懂thread dump文件中的线程信息

线程的状态是一个很重要的东西,因此thread dump中会显示这些状态,通过对这些状态的分析,能够得出线程的运行状况,进而发现可能存在的问题.线程的状态在Thread.State这个枚举类型中定义: public enum State { /** * Thread state for a thread which has not yet started. */ NEW, /** * Thread state for a runnable thread. A thread in the runn

shell 脚本---每隔几个小时查看日志文件中包含某些字符串的行数

在linux生产环境下,有如下这样的一个平常运维需要的工作. 每隔一段时间,比如两个小时,就要对每秒都要产生日志的日志文件(这里假设为testfile.out,其绝对路径为/home/panlm/shellpra/testfile.out)进行一个操作,这个操作是将日志中包含某些字符串的行给单独打印出来,并重新放在一个文件(这里的文件假设为out.log)中.这些需要匹配的字符串可以按这种方式表示"0x216000ab"其中ab为01到18的连续整数. 实现这样一个要求的做法主要有两步

在日志文件中输出当前时间

在代码中需要在出错的时候将错误写入到日志文件,而在写入错误时当然也需要将当前时间写入进去,下面的一段代码就是一个小实例. 1 #include <iostream> 2 #include <fstream> 3 #include <ctime> 4 5 using namespace std; 6 7 int main(int argc, char **argv) 8 { 9 ofstream fout("test.log", ios::out |

部署tomcat在windows服务器下,将tomcat控制台日志记录到日志文件中

在Linux系统中,Tomcat 启动后默认将很多信息都写入到 catalina.out 文件中,我们可以通过tail  -f  catalina.out 来跟踪Tomcat 和相关应用运行的情况. 在windows下,我们使用startup.bat启动Tomcat以后,会发现catalina日志与Linux记录的内容有很大区别,大多信息只输出到屏幕而没有记录到catalina.out里面. 本文的内容就是要实现在windows下,将相关的控制台输出记录到后台的catalina.out文件中以便