美文网首页
jstack线程分析

jstack线程分析

作者: 倪宝华 | 来源:发表于2018-06-11 14:54 被阅读0次

    一、Thread Dump日志的线程信息


    "resin-22129" 线程名称:如果使用 java.lang.Thread 类生成一个线程的时候,线程名称为 Thread-(数字) 的形式,这里是resin生成的线程;

    daemon 线程类型:线程分为守护线程 (daemon) 和非守护线程 (non-daemon) 两种,通常都是守护线程;

    prio=10 线程优先级:默认为5,数字越大优先级越高;

    tid=0x00007fbe5c34e000 JVM线程的id:JVM内部线程的唯一标识,通过 java.lang.Thread.getId()获取,通常用自增的方式实现;

    nid=0x4cb1 系统线程id:对应的系统线程id(Native Thread ID),可以通过 top 命令进行查看,现场id是十六进制的形式;

    waiting on condition 系统线程状态:这里是系统的线程状态,具体的含义见下面 系统线程状态 部分;

    [0x00007fbe4ff7c000] 起始栈地址:线程堆栈调用的其实内存地址;

    java.lang.Thread.State: WAITING (parking) JVM线程状态:这里标明了线程在代码级别的状态,详细的内容见下面的 JVM线程运行状态 部分。

    线程调用栈信息:下面就是当前线程调用的详细栈信息,用于代码的分析。堆栈信息应该从下向上解读,因为程序调用的顺序是从下向上的。

    二、系统线程的状态,以及各个状态代表的含义及其造成的原因


    重点关注:deadlock\waiting on condition\Waiting on monitor entry\Blocked(重点关注)   

    Deadlock

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

    runnable

    一般指该线程正在执行状态中,该线程占用了资源,正在处理某个操作,如通过SQL语句查询数据库、对某个文件进行写入等

    Waiting on condition

    等待某个资源或条件发生来唤醒自己。具体需要结合jstacktrace来分析,比如线程正在sleep,网络读写繁忙而等待

    线程正处于等待资源或等待某个条件的发生,具体的原因需要结合下面堆栈信息进行分析。

    (1)如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某种资源且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取,或者正在等待其他线程的执行等。

    (2)如果发现有大量的线程都正处于这种状态,并且堆栈信息中得知正等待网络读写,这是因为网络阻塞导致线程无法执行,很有可能是一个网络瓶颈的征兆:

    网络非常繁忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;

    网络可能是空闲的,但由于路由或防火墙等原因,导致包无法正常到达;

    所以一定要结合系统的一些性能观察工具进行综合分析,比如netstat统计单位时间的发送包的数量,看是否很明显超过了所在网络带宽的限制;观察CPU的利用率,看系统态的CPU时间是否明显大于用户态的CPU时间。这些都指向由于网络带宽所限导致的网络瓶颈。

    (3)还有一种常见的情况是该线程在 sleep,等待 sleep 的时间到了,将被唤醒。

    WAITING

    某一等待线程的线程状态。线程正在无期限地等待另一个线程来执行某一个特定的操作,线程因为调用下面的方法之一而处于等待状态:

    不带超时的 Object.wait 方法,日志中显示为 java.lang.Thread.State: WAITING (on object monitor)

    不带超时的 Thread.join 方法

    LockSupport.park 方法,日志中显示为 java.lang.Thread.State: WAITING (parking)

    Waiting on monitor entry:在等待获取锁

    在多线程的 JAVA程序中,实现线程之间的同步,就要说说Monitor。Monitor是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。下面这个图,描述了线程和 Monitor之间关系,以及线程的状态转换图: 

    从图中可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitorentry”,而在 “Wait Set”中等待的线程状态是“in Object.wait()”。

    Blocked:阻塞

    如果说系统的cpu耗的高,那么肯定是线程执行有死循环,那么此时要关注下Runable状态。


    三、补充一次线上问题


    具体问题如下:

    "hystrix-hestia-pay-gateway-pre-27" #1937 daemon prio=5 os_prio=0 tid=0x00007f3b78067800 nid=0x239e waiting on condition [0x00007f3b1e899000]

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

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

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

            at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)

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

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

            at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:924)

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

            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)

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

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

    "hystrix-hestia-pay-gateway-pre-26" #1934 daemon prio=5 os_prio=0 tid=0x00007f3b80827000 nid=0x2399 waiting on condition [0x00007f3b1e91b000]

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

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

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

    由于出现了大量的waiting on condition ,这是我们测试环境出现的问题,主要看parking to wait for  <0x00000000844d1ac8>,两个地址是一样的0x00000000844d1ac8

    jstack [进程pid]|grep -A 100 [线程pid]

    查看现在的每一个java进程的线程数

    echo 'pid--number' ;for pid in `ps ax | grep java | grep -v grep | awk '{print $1}'` ; do echo -n ${pid}--;pstree -p $pid | wc -l; done

    查看当前所有线程数量

    pstree -p|wc -l

    额外介绍一个查找最消耗cpu的java线程,jps 找到java进程PID

    命令:ps -mp pid -o THREAD,tid,time   或者  ps -Lfppid

    相关文章

      网友评论

          本文标题:jstack线程分析

          本文链接:https://www.haomeiwen.com/subject/uonceftx.html