JDK常用命令(二)jstack

Dump

  Dump文件是进程的内存镜像。可以把程序的执行状态通过调试器保存到dump文件中。Dump文件一般用来给驱动程序编写人员调试驱动程序用的,在java中用来分析正在运行的程序在内存中的堆栈信息。

jstack

  Jstack是Jdk自带的线程(栈)跟踪工具,主要用来查看Java线程的调用堆栈,可以用来分析线程问题(如死锁)。可根据指定java进程ID打印指定Java进程的线程堆栈信息。可以定位到线程阻塞、死循环、死锁等源头代码,java程序员必会技能之一。

  用法很简单:jstack pid,一般不加参数直接用就行

Options:
  -F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
  -m to print both java and native frames (mixed mode)
  -l long listing. Prints additional information about locks
  -h or -help to print this help message

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

java线程状态

  1.NEW,未启动的。不会出现在Dump中。
  2.RUNNABLE,在虚拟机内执行的。运行中状态,可能里面还能看到locked字样,表明它获得了某把锁。
  3.BLOCKED,受阻塞并等待监视器锁。被某个锁(synchronizers)給block住了。
  4.WATING,无限期等待另一个线程执行特定操作。等待某个condition或monitor发生,一般停留在park(), wait(), sleep(),join() 等语句里。
  5.TIMED_WATING,有时限的等待另一个线程的特定操作。和WAITING的区别是wait() 等语句加上了时间限制 wait(timeout)。
  6.TERMINATED,已退出的。

Monitor

  在多线程的 JAVA程序中,实现线程之间的同步,就是通过Monitor实现的。 Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。

  进入区(Entrt Set):表示线程通过synchronized要求获取对象的锁。如果对象未被锁住,则迚入拥有者;否则则在进入区等待。一旦对象锁被其他线程释放,立即参与竞争。

  拥有者(The Owner):表示某一线程成功竞争到对象锁。

  等待区(Wait Set):表示线程通过对象的wait方法,释放对象的锁,并在等待区等待被唤醒。

  从图中可以看出,一个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitor entry”,而在“Wait Set”中等待的线程状态是 “in Object.wait()”。 先看 “Entry Set”里面的线程。我们称被 synchronized保护起来的代码段为临界区。当一个线程申请进入临界区时,它就进入了 “Entry Set”队列。对应的 code就像:

1 synchronized(obj) {
2     //...
3 }

多线程分析

线程1获取到锁,处于RUNNABLE状态,线程2处于BLOCK状态

thread-1:locked <0x000000076bf62208>说明线程1对地址为0x000000076bf62208对象进行了加锁;

thread-2:waiting to lock <0x000000076bf62208> 说明线程2在等待地址为0x000000076bf62208对象上的锁;

thread-2:waiting for monitor entry [0x000000001e21f000]说明线程2是通过synchronized关键字进入了监视器的临界区,并处于"Entry Set"队列,等待monitor

线程1和2都处于WAITING状态

  线程1和2都是先locked <0x000000076bf62500>,再waiting on <0x000000076bf62500>,之所以先锁再等同一个对象,是因为wait方法需要先通过synchronized获得该地址对象的monitor;

  waiting on <0x000000076bf62500>说明线程执行了wait方法之后,释放了monitor,进入到"Wait Set"队列,等待其它线程执行地址为0x000000076bf62500对象的notify方法,并唤醒自己

死循环

1 package io.guangsoft.jstack;
2 
3 public class EndlessLoop {
4     public static void main(String args[]) {
5         while(true) {
6             System.out.println("endless loop...");
7         }
8     }
9 }

使用jstack查看堆栈信息

我们可以清晰的看到main线程处于RUNNABLE,并能看到是哪个包哪个类下的第几行。

线程等待

 1 package io.guangsoft.jstack;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 class TestTask implements Runnable {
 7     @Override
 8     public void run() {
 9         synchronized (this) {
10             try {
11                 wait();
12             } catch (InterruptedException e) {
13                 e.printStackTrace();
14             }
15         }
16     }
17 }
18 
19 public class Wait{
20     public static void main(String[] args) throws Exception {
21         ExecutorService ex = Executors.newFixedThreadPool(1);
22         ex.execute(new TestTask());
23     }
24 }

死锁

 1 package io.guangsoft.jstack;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 
 6 class Task implements Runnable {
 7     private int order;
 8     private Object obj1;
 9     private Object obj2;
10 
11     public Task(int order, Object obj1, Object obj2) {
12         this.order = order;
13         this.obj1 = obj1;
14         this.obj2 = obj2;
15     }
16 
17     public void test1() throws InterruptedException {
18         synchronized (obj1) {
19             //建议线程调取器切换到其它线程运行
20             Thread.yield();
21             synchronized (obj2) {
22                 System.out.println("test1");
23             }
24 
25         }
26     }
27     public void test2() throws InterruptedException {
28         synchronized (obj2) {
29             Thread.yield();
30             synchronized (obj1) {
31                 System.out.println("test2");
32             }
33 
34         }
35     }
36 
37     @Override
38     public void run() {
39         while (true) {
40             try {
41                 if(this.order == 1){
42                     this.test1();
43                 } else {
44                     this.test2();
45                 }
46             } catch (InterruptedException e) {
47                 e.printStackTrace();
48             }
49         }
50     }
51 }
52 
53 public class DeadLock {
54     public static void main(String[] args) throws Exception {
55         Object obj1 = new Object();
56         Object obj2 = new Object();
57         ExecutorService ex = Executors.newFixedThreadPool(10);
58         for (int i = 0; i < 10; i++) {
59             int order = i % 2 == 0 ? 1 : 0;
60             ex.execute(new Task(order, obj1, obj2));
61         }
62     }
63 }

posted @ 2019-03-14 17:48  光何  阅读(320)  评论(0编辑  收藏  举报