zoukankan      html  css  js  c++  java
  • 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 }

  • 相关阅读:
    犀牛书学习笔记(2):对象和数组
    犀牛书学习笔记(1):语法结构、数据类型和值、表达式和运算符
    小学了一下css hack
    git学习系列--六分之一
    稍览了一下CommonJS
    意识流_六分之一
    两升的心思系列之-----粒子的预备
    mybatis_延迟加载
    mybatis_动态SQL
    mybatis_mapper动态代理
  • 原文地址:https://www.cnblogs.com/guanghe/p/10531872.html
Copyright © 2011-2022 走看看