天天看點

如何使用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.

特别說明:

               如果有兩個或兩個以上的線程都通路了多個資源,而這些線程占用了一些資源的同時又在等待其它線程占用的資源,也就是                   說多個線程之間都持有了對方所需的資源,而又互相等待對方釋放的資源,在這種情況下就會出現死鎖。

               多個線程互相等待對方釋放對象鎖,此時就會出現死鎖