天天看点

如何使用jstack?线程的状态?

                                                      jstack的使用

文章目录

       一、作用

       二、语法

       三、线程状态

               a、如何查看pid进程内线程信息

               b、线程的状态

 一、作用

        作用:用于显示指定进程内线程的信息

 二、语法

       jstack [option] <pid>

       说明:

                option:命令选项,常用选项如下:

                -F:当’jstack [-l] pid’没有相应的时候强制打印栈信息,如果直接jstack无响应时,用于强制jstack),一般情况不需要使用

                -l:长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表,会使得JVM停顿得长久得多(可能会差很多倍,比如普通的jstack可能几毫秒和一次GC没区别,加了-l 就是近一秒的时间),-l 建议不        要用。一般情况不需要使用

               -m:打印java和native c/c++框架的所有栈信息.可以打印JVM的堆栈,显示上Native的栈帧,一般应用排查不需要使用

               pid:进程id

 三、线程状态

        a、如何查看pid进程内线程信息

         step1:获得进程的id,在这里获得eclipse的pid

       点击Win+R,输入cmd,在该页面处输入jps,得到进程的pid,如下图所示:

如何使用jstack?线程的状态?

        step2:得到pid进程内线程信息

        1、在eclipse运行如下代码:

package t;

public class Test {
	
	public static void main(String[] args) {
		while(true) {
		}
	}
}
           
        2、在cmd里面执行jstack pid命令,将得到的信息输入到outprint.txt里面,如下图所示:
如何使用jstack?线程的状态?
        3、打开outprint.txt查看pid进程内线程信息,部分信息如下:

2019-07-21 20:03:57

Full thread dump Java HotSpot(TM) Client VM (25.131-b11 mixed mode):

"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x08272c00 nid=0x10fc runnable [0x00000000]

   java.lang.Thread.State: RUNNABLE

   注:线程分为守护线程 (daemon) 和非守护线程 (non-daemon) 两种,通常都是守护线程;daemon 表示线程是否是守护线程

"C1 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x0826c000 nid=0x914 waiting on condition [0x00000000]

   java.lang.Thread.State: RUNNABLE

   注:prio:线程优先级

"Attach Listener" #6 daemon prio=5 os_prio=2 tid=0x08268400 nid=0x1c8c waiting on condition [0x00000000]

   java.lang.Thread.State: RUNNABLE

   注:os_prio:该线程对应的操作系统线程的优先级

          tid:Java中线程编号,JVM线程的id,JVM内部线程的唯一标识,通过 java.lang.Thread.getId()获取

"Signal Dispatcher" #5 daemon prio=9 os_prio=2 tid=0x08265c00 nid=0x3e4 runnable [0x00000000]

   java.lang.Thread.State: RUNNABLE

   注:nid:即native id,该线程对应的操作系统中本地线程编号,每一个java线程都有一个对应的操作系统线程

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x07bd5000 nid=0x1650 in Object.wait() [0x0893f000]

   java.lang.Thread.State: WAITING (on object monitor)

    at java.lang.Object.wait(Native Method)

    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)

    - locked <0x10267ac8> (a java.lang.ref.ReferenceQueue$Lock)

    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)

    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   注:Finalizer:线程状态

         WAITING (on object monitor):表示该线程处于等待状态,括号中的内容说明了导致等待的原因

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x07bcdc00 nid=0x1f60 in Object.wait() [0x087ff000]

   java.lang.Thread.State: WAITING (on object monitor)

        b、线程的状态: 
如何使用jstack?线程的状态?

           (1)、NEW:新创建了一个线程对象,但是还没有调用start()方法,jstack命令不会列出处于此状态的线程信                                                                      息。

           (2)、RUNNABLE:线程对象调用了start()方法,就进入了就绪状态,RUNNABLE只是表示线程是可运行的,在等待其他获取CPU的使用权,因为进程中的多个线程之间采用抢占式独立运行,而一个单核CPU在同一时刻,只能运行一个线程,如以下例子所示:      

package t;

public class Test {
	
		public static void main(String[] args) {
			new TimeThread().start();
			new CounterThread().start();
		}

}

class TimeThread extends Thread{
	
	@Override
	public void run() {
		while(true){
			System.out.println("时间线程~~~~~~~~~~~~~~~~~~");
		}	
		}
	}

class CounterThread extends Thread{

	@Override
	public void run() {
		while(true){
		  System.out.println("计数器线程*****************");
		}
	}
		
}
           
          代码运行结果:
如何使用jstack?线程的状态?

           由结果的不确定性,可以看线程是抢占式运行的,调用了start()方法,也不一定处于运行状态,要看是否获得CPU的执行权

          (3)、BLOCKED:线程处于阻塞状态,正在等待一个监视器锁(monitor lock)。通常情况下,是因为本线程与其他线程公用了一个锁。其他在线程正在使用这个锁进入某个synchronized同步方法块或者方法,而本线程进入这个同步代码块也需要这个锁,最终导致本线程处于阻塞状态,例子:

                      Ⅰ、运行如下代码:                   
package t;

public class Test {
		
	private static Object lock = new Object();
	
	public static void main(String[] args) {
		new Thread(new Task(), "线程1").start();
		new Thread(new Task(), "线程2").start();
	}
	
	static class Task implements Runnable {
		
		@Override
		public void run() {
			synchronized (lock) {
				count();
			}
		}
		
		private void count() {
			while (true) {
			}
		}
	}
}
           
                      Ⅱ、执行jps命令获取进程id,如下图所示,100是我需要查看的进程的id:
如何使用jstack?线程的状态?
                      Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                      Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下 

2019-07-21 23:44:10

//当前线程快照生成的时间

Full thread dump Java HotSpot(TM) Client VM (25.131-b11 mixed mode, sharing):

"DestroyJavaVM" #10 prio=5 os_prio=0 tid=0x0262c000 nid=0x1768 waiting on condition [0x00000000]

   java.lang.Thread.State: RUNNABLE

"线程2" #9 prio=5 os_prio=0 tid=0x14e06800 nid=0x200c waiting for monitor entry [0x157bf000]

   java.lang.Thread.State: BLOCKED (on object monitor)

    at t.Test$Task.run(Test.java:17)

    - waiting to lock <0x048badf0> (a java.lang.Object)

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

"线程1" #8 prio=5 os_prio=0 tid=0x14e06400 nid=0x21f0 runnable [0x1572f000]

   java.lang.Thread.State: RUNNABLE

    at t.Test$Task.count(Test.java:22)

    at t.Test$Task.run(Test.java:17)

    - locked <0x048badf0> (a java.lang.Object)

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

 由以上信息得:①线程1获取到锁,处于RUNNABLE状态;

                          ②线程2处于BLOCK状态,处于"Entry Set"队列,等待monitor

                          ③线程1、线程2共用一把锁

          (4)、WAITING:等待状态,等待某个condition或monitor发生,调用以下方法可能会导致一个线程处于等待状态:

                       wait() 不指定超时时间,例子:

                       Ⅰ、运行如下代码:         

package t;

public class Test {
	
	public static void main(String[] args) {
		Object lock = new Object();
		synchronized (lock) {
			try {
				lock.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
}
           
                       Ⅱ、执行jps命令获取进程id,如下图所示,9920是我需要查看的进程的id:
如何使用jstack?线程的状态?
                       Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                       Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下 :

2019-07-22 00:41:26

"main" #1 prio=5 os_prio=0 tid=0x0202c000 nid=0x2578 in Object.wait() [0x007cf000]

   java.lang.Thread.State: WAITING (on object monitor)

    at java.lang.Object.wait(Native Method)

    - waiting on <0x044baf40> (a java.lang.Object)

    at java.lang.Object.wait(Object.java:502)

    at t.Test.main(Test.java:9)

    - locked <0x044baf40> (a java.lang.Object)

由以上信息得:

                         ①、main线程先

locked <0x048ba168>

,再

waiting on <0x048ba168>

,之所以先锁再等同一个对象,是因为在Entrt                                   Set里的线程要通过竞争的方式和synchronized获得该地址对象的monitor,只有获得了monitor,才能执行                                             synchronized内的代码,此处为wait方法,被synchronized括着的部分就是线程执行临界区,每次仅能有一个线                                   程执行该临界区中的代码:当多个线程中的某个线程先拿到对象锁, 则该线程执行临界区内的代码,其他线程只能                                 在临界区外部等待,当此线程执行完临界区中的代码后,在临界区外部等待的其他线程开始再次竞争以获取对象                                     锁,进而执行临界区中的代码,但只能有一条线程“胜利”。

②、waiting on <0x048ba168>

说明线程执行了wait方法之后,释放了monitor,进入到"Wait Set"队列,等待其它线程                                 执行地址为

0x048ba168

对象的notify方法,并唤醒自己

特别说明:

                       wait()和notify()一系列的方法,是属于对象的,不是属于线程的。它们用在线程同步时,synchronized语句块中

                       wait()意思是说,我等会儿再用这把锁,CPU也让给你们,我先休息一会儿!

                       notify()意思是说,我用完了,你们谁用?

                       也就是说,wait()会让出对象锁,同时,当前线程休眠,等待被唤醒,如果不被唤醒,就一直等在那儿。

                        notify()并不会让当前线程休眠,但会唤醒休眠的线程。

                       join() 不指定超时时间,例子:

                       Ⅰ、运行如下代码:

public class Test {

	public static void main(String[] args) {
		CountThread countThread = new CountThread();//返回当前正在执行的线程对象
		countThread.start();
		try {
			countThread.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	static class CountThread extends Thread{
	
		@Override
		public void run() {
			while(true) {
				
			}
		}
	}
}
           
                       Ⅱ、执行jps命令获取进程id,如下图所示9976是我需要查看的进程的id:
如何使用jstack?线程的状态?
                       Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                       Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下

"main" #1 prio=5 os_prio=0 tid=0x0287c000 nid=0x26d8 in Object.wait() [0x00ddf000]

   java.lang.Thread.State: WAITING (on object monitor)

    at java.lang.Object.wait(Native Method)

    - waiting on <0x04cbc338> (a t.Test$CountThread)

    at java.lang.Thread.join(Thread.java:1252)

    - locked <0x04cbc338> (a t.Test$CountThread)

    at java.lang.Thread.join(Thread.java:1326)

    at t.Test.main(Test.java:9)

特别说明:join方法:执行该方法的线程进入阻塞状态,直到调用该方法的线程结束后再由阻塞转为就绪状态,如图所示

如何使用jstack?线程的状态?

                        park() 例子:

                       Ⅰ、运行如下代码:

import java.util.concurrent.locks.LockSupport;

public class Test{
	
	public static void main(String[] args) {
		LockSupport.park();//禁用执行该行代码的线程。
	}
}
           
                       Ⅱ、执行jps命令获取进程id,如下图所示,9976是我需要查看的进程的id:
如何使用jstack?线程的状态?
                       Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                       Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下 

"main" #1 prio=5 os_prio=0 tid=0x0072c000 nid=0x261c waiting on condition [0x0060f000]

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

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

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

    at t.Test.main(Test.java:8)

特别说明:

                 waiting on condition:等待资源,或等待某个条件的发生,出现 Wait on condition的常见情况是该线程在 sleep,等待                       sleep的时间到了时候,将被唤醒。

           (5)、TIMED_WAITING:线程等待指定的时间,对于以下方法的调用,可能会导致线程处于这个状态:

                        wait(long timeout) 指定超时时间,例子:

                       Ⅰ、运行如下代码:

package t;

public class Test {
	
	public static void main(String[] args) {
		Object lock = new Object();
		synchronized (lock) {
			try {
				lock.wait(Long.MAX_VALUE);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
           
                       Ⅱ、执行jps命令获取进程id,如下图所示,9200是我需要查看的进程的id:
如何使用jstack?线程的状态?
                       Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                       Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下

"main" #1 prio=5 os_prio=0 tid=0x024ec000 nid=0x217c in Object.wait() [0x0240f000]

   java.lang.Thread.State: TIMED_WAITING (on object monitor)

    at java.lang.Object.wait(Native Method)

    - waiting on <0x04abaf50> (a java.lang.Object)

    at t.Test.main(Test.java:9)

    - locked <0x04abaf50> (a java.lang.Object)

特别说明:object.wait()与wait(long)的区别:

                  object.wait()是属于类实例(Object及其子类实列,也包括Class类实例)的方法。

                  其基本语义是使当前线程等待,直到被通知,默认是this.wait()。

                  实现细节是把当前线程放入阻塞线程队列中,并把当前线程注册为指定对象的监听器,并锁释放指定对象的锁;

                  当被notify/notifyAll通知时,重新争取指定对象的锁,并把当前线程从指定对象的监听器中移除,把当前线程从阻塞队列放                    入就绪队列,等待被调度。

                  此方法必须在sychronized代码块中,且锁定的对象要与等待通知来源的对象一致。

                  而wait(long)方法阻塞时放入的是就绪队列,等待时间到期或被通知就可被调度,其他与wait()方法相同。

                        join(long millis) 指定超时时间,例子:

                         Ⅰ、运行如下代码:                    

public class Test {

	public static void main(String[] args) {
		CountThread countThread = new CountThread();
		countThread.start();
		try {
			countThread.join(Long.MAX_VALUE);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	static class CountThread extends Thread{
	
		@Override
		public void run() {
			while(true) {
				
			}
		}
	}
}
           
                       Ⅱ、执行jps命令获取进程id,如下图所示,4000是我需要查看的进程的id:
如何使用jstack?线程的状态?
                       Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                       Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下

"main" #1 prio=5 os_prio=0 tid=0x00c3c000 nid=0x1ddc in Object.wait() [0x00bef000]

   java.lang.Thread.State: TIMED_WAITING (on object monitor)

    at java.lang.Object.wait(Native Method)

    - waiting on <0x04abc350> (a t.Test$CountThread)

    at java.lang.Thread.join(Thread.java:1260)

    - locked <0x04abc350> (a t.Test$CountThread)

    at t.Test.main(Test.java:9)

从以上信息可知:join()、join(long millis)方法的实现都使用了wait方法

特别说明:join()、join(long millis)

                  假如在main线程中,调用thread.join方法,则main方法会等待thread线程执行完毕或者等待一定的时间。如果调用的是无                    参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的时间,不用等待thread执行                    完毕

                       sleep(long millis) 指定超时时间,例子:

                      Ⅰ、运行如下代码:

public class Test {
	
	public static void main(String[] args) {
		try {
			Thread.sleep(Long.MAX_VALUE);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
           
                       Ⅱ、执行jps命令获取进程id,如下图所示,9648是我需要查看的进程的id:
如何使用jstack?线程的状态?
                       Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                       Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下

"main" #1 prio=5 os_prio=0 tid=0x0079c000 nid=0x25e8 waiting on condition [0x0081f000]

   java.lang.Thread.State: TIMED_WAITING (sleeping)

    at java.lang.Thread.sleep(Native Method)

    at t.Test.main(Test.java:7)

特别说明:

                 sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。

                 但是sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个                   对象

                       parkNanos(long nanos) 例子:

                       Ⅰ、运行如下代码:

import java.util.concurrent.locks.LockSupport;

public class Test{
	
	public static void main(String[] args) {
		LockSupport.parkNanos(Long.MAX_VALUE);//在规定的截止时间(单位:纳秒,1毫秒=1,000,000纳秒)之前,执行该行代码的线程被禁用。
	}
}
           
                       Ⅱ、执行jps命令获取进程id,如下图所示,9596是我需要查看的进程的id:
如何使用jstack?线程的状态?
                       Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                       Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下

"main" #1 prio=5 os_prio=0 tid=0x025ac000 nid=0x2174 waiting on condition [0x00a0f000]

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

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

    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:338)

    at t.Test.main(Test.java:8)

                       parkUntil(long deadline) 例子:

                      Ⅰ、运行如下代码:

import java.util.concurrent.locks.LockSupport;

public class Test{
	
	public static void main(String[] args) {
		LockSupport.parkUntil(Long.MAX_VALUE);//在规定的截止时间(单位:毫秒)之前,执行该行代码的线程被禁用。
	}
}
           
                      Ⅱ、执行jps命令获取进程id,如下图所示,8580是我需要查看的进程的id:
如何使用jstack?线程的状态?
                      Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                      Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下

"main" #1 prio=5 os_prio=0 tid=0x007cc000 nid=0x135c waiting on condition [0x0077f000]

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

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

    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:338)

    at t.Test.main(Test.java:8)

             (6)、TERMINATED:线程终止。

             死锁

               ​​​Ⅰ、运行如下代码:

public class Test {
	// 创建两个线程之间竞争使用的对象
	private static Object lock1 = new Object();
	private static Object lock2 = new Object();

	public static void main(String[] args) {
		new ShareThread1().start();
		new ShareThread2().start();
	}

	static class ShareThread1 extends Thread {
		public void run() {
			synchronized (lock1) {
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (lock2) {
					System.out.println("ShareThread1");
				}
			}
		}
	}

	static class ShareThread2 extends Thread {
		public void run() {
			synchronized (lock2) {
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (lock1) {
					System.out.println("ShareThread2");
				}
			}
		}
	}
}
           
                      Ⅱ、执行jps命令获取进程id,如下图所示,11064是我需要查看的进程的id:
如何使用jstack?线程的状态?
                      Ⅲ、执行jstack pid命令,输入到out.txt文本里面,便于分析,如下所示:
如何使用jstack?线程的状态?
                      Ⅳ、打开out.txt文本查看pid进程内线程信息,部分信息如下 

Found one Java-level deadlock:

=============================

"Thread-1":

  waiting to lock monitor 0x0270b8cc (object 0x04abacd0, a java.lang.Object),

  which is held by "Thread-0"

"Thread-0":

  waiting to lock monitor 0x0270abac (object 0x04abacd8, a java.lang.Object),

  which is held by "Thread-1"

Java stack information for the threads listed above:

===================================================

"Thread-1":

    at t.Test$ShareThread2.run(Test.java:37)

    - waiting to lock <0x04abacd0> (a java.lang.Object)

    - locked <0x04abacd8> (a java.lang.Object)

"Thread-0":

    at t.Test$ShareThread1.run(Test.java:22)

    - waiting to lock <0x04abacd8> (a java.lang.Object)

    - locked <0x04abacd0> (a java.lang.Object)

Found 1 deadlock.

特别说明:

               如果有两个或两个以上的线程都访问了多个资源,而这些线程占用了一些资源的同时又在等待其它线程占用的资源,也就是                   说多个线程之间都持有了对方所需的资源,而又相互等待对方释放的资源,在这种情况下就会出现死锁。

               多个线程互相等待对方释放对象锁,此时就会出现死锁