精华内容
下载资源
问答
  • 通过jstack日志分析和问题排查

    千次阅读 2019-05-08 15:46:06
    整个服务系统发生雪崩,系统彻底访问不了),一开始怎么都找不到问题的根源,日志的表现形式是dubbo线程池用完了,那么具体是什么导致的没有找到,后然通过jstack日志分析才找到问题的根源,根源就是系统日志代码写...

    前段事件公司出现了一个严重故障(调用dubbo服务一直处于超时,整个服务系统发生雪崩,系统彻底访问不了),一开始怎么都找不到问题的根源,日志的表现形式是dubbo线程池用完了,那么具体是什么导致的没有找到,后然通过jstack日志分析才找到问题的根源,根源就是系统日志代码写有问题。通过这个故障我们来了解下如何通过jstack日志分析线上问题。首先了解下jstack

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

    死锁, Deadlock(重点关注) 

    执行中,Runnable   

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

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

    暂停,Suspended

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

    阻塞, Blocked(重点关注)  

    停止,Parked

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

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

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

    Waiting on condition:该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写,比如当网络数据没有准备好读时,线程处于这种等待状态,而一旦有数据准备好读之后,线程会重新激活,读取并处理数据。在 Java引入 NewIO之前,对于每个网络连接,都有一个对应的线程来处理网络的读写操作,即使没有可读写的数据,线程仍然阻塞在读写操作上,这样有可能造成资源浪费,而且给操作系统的线程调度也带来压力。在 NewIO里采用了新的机制,编写的服务器程序的性能和可扩展性都得到提高。

            如果发现有大量的线程都在处在 Wait on condition,从线程 stack看, 正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。一种情况是网络非常忙,几 乎消耗了所有的带宽,仍然有大量数据等待网络读 写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。所以要结合系统的一些性能观察工具来综合分析,比如 netstat统计单位时间的发送包的数目,如果很明显超过了所在网络带宽的限制 ; 观察 cpu的利用率,如果系统态的 CPU时间,相对于用户态的 CPU时间比例较高;如果程序运行在 Solaris 10平台上,可以用 dtrace工具看系统调用的情况,如果观察到 read/write的系统调用的次数或者运行时间遥遥领先;这些都指向由于网络带宽所限导致的网络瓶颈。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。

    locked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。

    Waiting for monitor entry 和 in Object.wait():Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。

    各种情况演示分享

     

       分享dump日志我们需要找到一个分析工具,一直没找到好的分析工具后然我同事分享了我一个是IBM开发的工具叫

        "IBM Thread and Monitor Dump Analyzer for Java" 下载地址:https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=2245aa39-fa5c-4475-b891-14c205f7333c

        

    1.Deadlock(死锁) 

        演示代码  

    public class DiedsynchronizedTest {
            public static void main(String[] args) {
                Thread a = new ThreadRunA();
                Thread b = new ThreadRunB();
                a.start();
                b.start();
            }
        }
        class ThreadRunA extends Thread {
            public void run() {
                System.out.println("================A===================");
                synchronized (A.A) {
                    System.out.println("我要开始执行任务A。。。。" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (B.B) {
                    }
                    System.out.println("我在执行任务结束了A。。。。" + Thread.currentThread().getName() + ":" + B.B.hashCode() + ":"
                                       + A.A.hashCode());
                }
            }
        }
        class ThreadRunB extends Thread {
            public void run() {
                System.out.println("================B===================");
                synchronized (B.B) {
                    System.out.println("我要开始执行任务B。。。。" + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (A.A) {
                    }
                    System.out.println("我在执行任务结束了B。。。。" + Thread.currentThread().getName() + ":" + B.B + ":" + A.A);
                }
            }
        }
        class A {
            static Integer A = new Integer(1);
        }
        class B {
            static Integer B = new Integer(1);
        }

        这是个简单的死循环的代码,我们用jstack命令dump他的信息导入分析工具如图

        

        从图上能清醒的看到Thread-1和Thread-0现实 Deadlock,而且还帮你定位到了具体的类和行数。

        所以我们在系统中实用锁的时候,一定要考虑到多线程并发,避免出现交叉调用。

        

    2.Runnable 

        有时候我们发现CPU性能消耗很厉害,系统日志也看不出什么问题,那么这个时候我们要坚持运行中的线程有没有出现异常,

        下面我们看下代码

    public class DumpWhileDemo {
            public static void main(String[] args) {
                new Thread(new WhileThread()).start();
                System.out.println();
            }
        }
        class WhileThread implements Runnable {
            @Override
            public void run() {
                while (true) {
                    System.out.println("Thread");
                }
            }
        }

        这段代码我们可以看出new一个线程,线程里面是无线循环,执行main方法后,CPU会直线上升。可以通过linux的top命令看出来。

        我们jstack命令dump它的信息导入查看如下图

        

        我们能看到线程Thread-0的Method方法列显示的是我们的自己写的类,其他两个run的的都显示NO JAVA STACK.

        如果我还是怀疑Thread-0方法那么我多dump几次查看,如果依旧还是这样那么可以说明此访问有问题。

        因为我们使用jstack的时候打印的是当时的状态,所以多打印几次基本能确定是否是有异常方法.不要天真的认为Runnable状态的就

        没问,一切皆有可能。

         

    3.Waiting on monitor entry 和 in Object.wait()

        这个我就直接拿我们线上出的故障来和大家分享下,当时我们分析的时候吧dump日志下载到本地,然后导入到工具里面,看下图

        

        

        线上我们可以清楚的看到DubboServerHandler有200的线程(dubbo服务默认线程池就200,这个了解dubbo的同学都应该清楚),

        我们再看右侧报错的内容backlog日志出问题了,后面我开发同学进一步分析是dubbo日志打印没有控制线程数量。

        

     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()”。 

    4. Blocked  

        还是上面说的那个故障,这个时候线程已经阻塞了看下图,导致阻塞的原因就是就是200个默认线程一直没有释放或者,

        等待进入的线程太多

        

        

     总结

     Java线程 DUMP的基本知识和分析的基本方法,并且解释了如何利用线程的 DUMP信息,以及结合操作系统的各种资源使用情况,

    分析程序的性能问题,从而达到改进程序,提高性能的目的。  

    展开全文
  • 含义如下所示:Deadlock:死锁线程,一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。Runnable:一般指该线程正在执行状态中,该线程占用了资源,...具体原因需结合 stacktrace来分析。如果堆...

    含义如下所示:

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

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

    Waiting on condition:等待资源,或等待某个条件的发生。具体原因需结合 stacktrace来分析。

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

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

    如果发现有大量的线程都在处在 Wait on condition,从线程 stack看,正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。

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

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

    另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。

    Blocked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。

    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()”。

    b8b1562fe3661bddc3f40db93d770be5.png

    图1 A Java Monitor

    综合示范二: W aiting 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);

    ……

    }

    }

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

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

    展开全文
  • 主要介绍了Java线程Dump分析工具jstack解析及使用场景,具有一定借鉴价值,需要的朋友可以参考下
  • jstack堆栈日志分析

    千次阅读 2019-01-12 16:33:58
    jstack Dump 日志文件中的线程状态, dump 文件里,值得关注的线程状态有: 死锁,Deadlock(重点关注) 执行中,Runnable 等待资源,Waiting on condition(重点关注) 等待获取监视器,Waiting on ...

    参照文章来源:

    https://www.cnblogs.com/aligege/p/7550478.html
    http://blog.csdn.net/zhangzhaokun/article/details/6395557
    http://www.cnblogs.com/zhengyun_ustc/archive/2013/03/18/tda.html
    http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html

    一 线程状态

    关于线程状态的描述推荐书籍

    深入理解Java虚拟机 第12章 Java内存模型与线程 12.4.3 状态转换

    章节描述.

    二、线程的entry sets 和 wait sets

    有关Java的线程锁与entry set和wait set的关系,抑或是说这个图包含了Java线程的奥秘,不懂这个图或者是没有见过这个图的话,只能说明对于Java的线程锁还是一知半解的。

    线程的entry sets 和 wait sets

    (1)所有期待获得锁的线程,在锁已经被其它线程拥有的时候,这些期待获得锁的线程就进入了Object Lock的entry set区域。

    (2)所有曾经获得过锁,但是由于其它必要条件不满足而需要wait的时候,线程就进入了Object Lock的wait set区域 。

    (3)在wait set区域的线程获得Notify/notifyAll通知的时候,随机的一个Thread(Notify)或者是全部的Thread(NotifyALL)从Object Lock的wait set区域进入了entry set中。

    (4)在当前拥有锁的线程释放掉锁的时候,处于该Object Lock的entryset区域的线程都会抢占该锁,但是只能有任意的一个Thread能取得该锁,而其他线程依然在entry set中等待下次来抢占到锁之后再执行。

    三、实例分析

    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文件中的线程状态含义及注意事项

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

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

    3. Blocked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。

    4. Waiting on condition:等待资源,或等待某个条件的发生。具体原因需结合 stacktrace来分析。

      (1) :如果堆栈信息明确是应用代码,则证明该线程正在等待资源。一般是大量读取某资源,且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取。
      (2): 又或者,正在等待其他线程的执行等。
      (3): 如果发现有大量的线程都在处在 Wait on condition,从线程 stack看,正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。

      i:一种情况是网络非常忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写
      ii:另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。
      

      (4): 另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。

    5. 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)
     1. 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)
     1. waiting on <0x00000000aa672478> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
     2. 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> )。

    1. 从堆栈信息看,是正在清理 remote references to remote objects ,引用的租约到了,分布式垃圾回收在逐一清理呢。
    展开全文
  • 原博地址:http://www.ccblog.cn/84.htm简介jstack用于生成java虚拟机当前时刻的线程快照。... 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情

    原博地址:http://www.ccblog.cn/84.htm

    简介

    jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

    一:jstack

    jstack命令的语法格式: jstack 。可以用jps查看java进程id。这里要注意的是:

    1. 不同的 JAVA虚机的线程 DUMP的创建方法和文件格式是不一样的,不同的 JVM版本, dump信息也有差别。

    2. 在实际运行中,往往一次 dump的信息,还不足以确认问题。建议产生三次 dump信息,如果每次 dump都指向同一个问题,我们才确定问题的典型性。

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

    1:dump 文件里,值得关注的线程状态有
    
    
    死锁, Deadlock(重点关注) 
    
    执行中,Runnable   
    
    等待资源, Waiting on condition(重点关注) 
    
    等待获取监视器, Waiting on monitor entry(重点关注)
    
    暂停,Suspended
    
    对象等待中,Object.wait() 或 TIMED_WAITING
    
    阻塞, Blocked(重点关注)  
    
    停止,Parked
    
    
    2:Dump文件中的线程状态含义及注意事项
    
    
    
    Deadlock:死锁线程,一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。
    
    
    
    Runnable:一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换。
    
    
    
    Waiting on condition:该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写,比如当网络数据没有准备好读时,线程处于这种等待状态,而一旦有数据准备好读之后,线程会重新激活,读取并处理数据。在 Java引入 NewIO之前,对于每个网络连接,都有一个对应的线程来处理网络的读写操作,即使没有可读写的数据,线程仍然阻塞在读写操作上,这样有可能造成资源浪费,而且给操作系统的线程调度也带来压力。在 NewIO里采用了新的机制,编写的服务器程序的性能和可扩展性都得到提高。
    
        如果发现有大量的线程都在处在 Wait on condition,从线程 stack看, 正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。一种情况是网络非常忙,几 乎消耗了所有的带宽,仍然有大量数据等待网络读 写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。所以要结合系统的一些性能观察工具来综合分析,比如 netstat统计单位时间的发送包的数目,如果很明显超过了所在网络带宽的限制 ; 观察 cpu的利用率,如果系统态的 CPU时间,相对于用户态的 CPU时间比例较高;如果程序运行在 Solaris 10平台上,可以用 dtrace工具看系统调用的情况,如果观察到 read/write的系统调用的次数或者运行时间遥遥领先;这些都指向由于网络带宽所限导致的网络瓶颈。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
    
    
    
    
    
    locked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。
    
    
    
    Waiting for monitor entry 和 in Object.wait():Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。
    

    三:各种情况演示分享

    分享dump日志我们需要找到一个分析工具,一直没找到好的分析工具后然我同事分享了我一个是IBM开发的工具叫

    "IBM Thread and Monitor Dump Analyzer for Java" 下载地址:https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=2245aa39-fa5c-4475-b891-14c205f7333c
    
    
    1:Deadlock(死锁)
    
    
    
    演示代码
    

    public class DiedsynchronizedTest {
    public static void main(String[] args) {
    Thread a = new ThreadRunA();
    Thread b = new ThreadRunB();
    a.start();
    b.start();
    }
    }
    class ThreadRunA extends Thread {
    public void run() {
    System.out.println(“================A===================”);
    synchronized (A.A) {
    System.out.println(“我要开始执行任务A。。。。” + Thread.currentThread().getName());
    try {
    Thread.sleep(5000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    synchronized (B.B) {
    }
    System.out.println(“我在执行任务结束了A。。。。” + Thread.currentThread().getName() + “:” + B.B.hashCode() + “:”
    + A.A.hashCode());
    }
    }
    }
    class ThreadRunB extends Thread {
    public void run() {
    System.out.println(“================B===================”);
    synchronized (B.B) {
    System.out.println(“我要开始执行任务B。。。。” + Thread.currentThread().getName());
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    synchronized (A.A) {
    }
    System.out.println(“我在执行任务结束了B。。。。” + Thread.currentThread().getName() + “:” + B.B + “:” + A.A);
    }
    }
    }
    class A {
    static Integer A = new Integer(1);
    }
    class B {
    static Integer B = new Integer(1);
    }

    这是个简单的死循环的代码,我们用jstack命令dump他的信息导入分析工具如图
    
    
    
    从图上能清醒的看到Thread-1和Thread-0现实 Deadlock,而且还帮你定位到了具体的类和行数。
    
    所以我们在系统中实用锁的时候,一定要考虑到多线程并发,避免出现交叉调用。
    
    
    2:Runnable 
    
    
    有时候我们发现CPU性能消耗很厉害,系统日志也看不出什么问题,那么这个时候我们要坚持运行中的线程有没有出现异常,
    
    下面我们看下代码
    

    public class DumpWhileDemo {
    public static void main(String[] args) {
    new Thread(new WhileThread()).start();
    System.out.println();
    }
    }
    class WhileThread implements Runnable {
    @Override
    public void run() {
    while (true) {
    System.out.println(“Thread”);
    }
    }
    }

    这段代码我们可以看出new一个线程,线程里面是无线循环,执行main方法后,CPU会直线上升。可以通过linux的top命令看出来。
    
    我们jstack命令dump它的信息导入查看如下图
    
    
    
    我们能看到线程Thread-0的Method方法列显示的是我们的自己写的类,其他两个run的的都显示NO JAVA STACK.
    
    如果我还是怀疑Thread-0方法那么我多dump几次查看,如果依旧还是这样那么可以说明此访问有问题。
    
    因为我们使用jstack的时候打印的是当时的状态,所以多打印几次基本能确定是否是有异常方法.不要天真的认为Runnable状态的就
    
    没问,一切皆有可能。
    
    
    3:Waiting on monitor entry 和 in Object.wait()
    
    
    这个我就直接拿我们线上出的故障来和大家分享下,当时我们分析的时候吧dump日志下载到本地,然后导入到工具里面,看下图
    
    
    
    
    
    线上我们可以清楚的看到DubboServerHandler有200的线程(dubbo服务默认线程池就200,这个了解dubbo的同学都应该清楚),
    
    我们再看右侧报错的内容backlog日志出问题了,后面我开发同学进一步分析是dubbo日志打印没有控制线程数量。
    

    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()”。

    4、 Blocked  
    
    还是上面说的那个故障,这个时候线程已经阻塞了看下图,导致阻塞的原因就是就是200个默认线程一直没有释放或者,
    
    等待进入的线程太多
    

    总结

    Java线程 DUMP的基本知识和分析的基本方法,并且解释了如何利用线程的 DUMP信息,以及结合操作系统的各种资源使用情况,

    分析程序的性能问题,从而达到改进程序,提高性能的目的。

    展开全文
  • 13.7.深入理解jstack日志 转自:https://blog.csdn.net/iteye_5603/article/details/82652200 在分析线上问题时常使用到jstack 命令将当时Java应用程序的线程堆栈dump出来。 面对jstack 日志,我们如何查看? 首先要...
  • 一般问题发生时我们都会去查看日志,经常遇到没有日志的情况(此时服务无法响应client请求),甚至要去找几个小时前的日志现象发生时,有些接口甚至没有日志打印,查找起来很困难,利用jvm的线程栈工具jstack对于...
  • 使用方法很简单,直接将dump出来的堆栈信息,打开,便可分析
  • 深入理解jstack日志

    千次阅读 2016-05-18 20:35:01
    分析线上问题时常使用到jstack &lt;PID&gt;命令将当时Java应用程序的线程堆栈dump出来。面对jstack 日志,我们如何查看?   首先要清楚线程的状态线程的状态有:new、runnable、running、waiting、...
  • jstack日志深入理解

    2020-12-22 08:03:30
    总结: 对于jstack日志,我们要着重关注如下关键信息 Deadlock:表示有死锁 Waiting on condition:等待某个资源或条件发生来唤醒自己。具体需要结合jstacktrace来分析,比如线程正在sleep,网络读写繁忙而等待 ...
  • jstack 日志微解

    2021-01-21 11:12:10
    3:jstack日志下载,使用工具分析:jstack -l pid << my.txt 先建好my.txt文件。 4:使用工具打开my.txt文件解析查看: 5:查看死锁原因: 6:对照代码分析: package com.jstack; public class ...
  • jstack Dump 日志文件中的线程状态dump 文件里,值得关注的线程状态有:死锁,Deadlock(重点关注)执行中,Runnable等待资源,Waiting on condition(重点关注)等待获取监视器,Waiting on monitor entry(重点关注)...
  • 下面我们先从第一个例子开始分析,然后再列出不同线程状态的含义以及注意事项,最后再补充两个实例。 综合 示范一: Waiting to lock 和 Blocked 实例如下: "RMI TCP Connection(267865)-172.16.5.25...
  • jstack生成的Thread Dump日志.docx 系统线程状态 (Native Thread Status) 系统线程有如下状态: deadlock 死锁线程,一般指多个线程调用期间进入了相互资源占用,导致一直等待无法释放的情况。 ...
  • 展开全部转自 ...线程状态jstack 线程里,值得关注的线程状态有32313133353236313431303231363533e4b893e5b19e31333363376464:死锁,Deadlock(重点关注)执行中,Runnable等待资源,Waitingon c...
  • GC日志 gceasy.io Jstack日志 fastthread.io
  • 1:进入容器, docker exec -it 容器名 /bin/bash 2: top 查看 pid, 如图所标为8 3: find / -name jstack , 查看...5:日志到手,当然就可以放到copy到宿主机上去,然后再下载到桌面上慢慢分析了,我这里拷..
  • 前言 前面写了jmap 和 visualVM, jstack在实际生产中也用到过,不过当时都记在印象笔记了~ 最近整理拿出来。 使用
  • 这个线程cpu占用很高 "[ACTIVE] ExecuteThread: '22' for queue: 'weblogic.kernel.Default (self-tuning)'" id=76 idx=0x11c tid=828 prio=5 alive, native_blocked, daemon at java/io/WinNTFileSystem....
  • JVM分析工具——jstack实践一、不是万能的jstack企业级的Java程序中,java程序出现性能低下甚至直接崩溃时,就不能像解决业务bug那样,从行为表现上来修复问题了。性能问题一般是jvm资源告罄的表现,需要结合jvm的...
  • 近期发现tomcat 的cpu 突然飙高,想在cpu 暴涨时候输出 jstack 日志分析。通过资料查询 可以用 top top 命令可以查询服务各种性能信息。Java 堆栈信息可用 jstack -l [pid] >> [文件名].log jstack 命令...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,001
精华内容 4,400
关键字:

jstack日志分析