简介

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  <pid>。可以用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信息,以及结合操作系统的各种资源使用情况,

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

转自http://www.ccblog.cn/84.htm

最新文章

  1. CI-持续集成(2)-软件工业“流水线”技术实现
  2. sqlite3使用(一)
  3. LA 3695 Distant Galaxy
  4. CentOS 7.0 安装 python3.X 脚本
  5. C语言之 短路原则
  6. Maven项目问题
  7. JavaScript初探之AJAX的应用
  8. golang文件操作
  9. SQL Server数据库读写分离提高并发性
  10. nginx Provisional headers are shown
  11. Linux IDR机制【转】
  12. 洛谷P1265 公路修建(Prim)
  13. GoDaddy账户间域名转移PUSH以及ACCEPT接受域名过户方法
  14. luogu1540 [NOIp2011]机器翻译 (队列)
  15. 61. oracle给用户解锁
  16. hdu 5018
  17. Android中全屏 取消标题栏,TabHost中设置NoTitleBar的三种方法(转)
  18. 转asp.net中的App_GlobalResources和App_LocalResources使用
  19. 有关索引的DMV(转)
  20. C#语言-05.委托和事件

热门文章

  1. 【模拟7.27】题(liu_runda的神题)(卡特兰数,组合数)
  2. Java程序安装失败
  3. 解析 Nebula Graph 子图设计及实践
  4. 在vs中调试关闭之后不关闭页面
  5. Excel的布尔值运算
  6. Docker学不会?不妨看看这篇文章
  7. MyBatis:MyBatis-Plus条件构造器EntityWrapper
  8. mysql被收购 用mariadb (转)
  9. 比较app版本大小----python
  10. 性能基准DevOps之如何提升脚本执行效率