jstack 線程狀態詳解

jatsck 用法

#jstack -h
Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

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

在這裏插入圖片描述

線程狀態

狀態 含義 觸發方法 線程動作(線程狀態產生的原因) 備註
NEW Thread state for a thread which has not yet started. 不會出現在Dump中
RUNNABLE Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor. runnable
BLOCKED Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling Object.wait. waiting for monitor entry
WAITING Thread state for a waiting thread. Object.wait with no timeout => WAITING (on object monitor) in Object.wait() A thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object.
Thread.join with no timeout=> WAITING (on object monitor) in Object.wait() A thread that has called Thread.join() is waiting for a specified thread to terminate.
LockSupport.park=> WAITING(parking) waiting on condition
TIMED_WAITING Thread state for a waiting thread with a specified waiting time. Thread.sleep=> TIMED_WAITING (sleeping) waiting on condition
Object.wait with timeout=> TIMED_WAITING (on object monitor) in Object.wait()
Thread.join with timeout=> TIMED_WAITING (on object monitor) in Object.wait()
LockSupport.parkNanos=> TIMED_WAITING (parking) waiting on condition
LockSupport.parkUntil=> TIMED_WAITING (parking) waiting on condition
TERMINATED Thread state for a terminated thread. The thread has completed execution. 不會出現在Dump中

一圖以庇之

在這裏插入圖片描述

系統線程狀態 (Native Thread Status)

系統線程有如下狀態:

  • deadlock
    死鎖線程,一般指多個線程調用期間進入了相互資源佔用,導致一直等待無法釋放的情況。

  • runnable
    一般指該線程正在執行狀態中,該線程佔用了資源,正在處理某個操作,如通過SQL語句查詢數據庫、對某個文件進行寫入等。

  • blocked
    線程正處於阻塞狀態,指當前線程執行過程中,所需要的資源長時間等待卻一直未能獲取到,被容器的線程管理器標識爲阻塞狀態,可以理解爲等待資源超時的線程。

  • waiting on condition
    線程正處於等待資源或等待某個條件的發生,具體的原因需要結合下面堆棧信息進行分析。

    1. 如果堆棧信息明確是應用代碼,則證明該線程正在等待資源,一般是大量讀取某種資源且該資源採用了資源鎖的情況下,線程進入等待狀態,等待資源的讀取,或者正在等待其他線程的執行等。
    2. 如果發現有大量的線程都正處於這種狀態,並且堆棧信息中得知正等待網絡讀寫,這是因爲網絡阻塞導致線程無法執行,很有可能是一個網絡瓶頸的徵兆:
      • 網絡非常繁忙,幾乎消耗了所有的帶寬,仍然有大量數據等待網絡讀寫;
      • 網絡可能是空閒的,但由於路由或防火牆等原因,導致包無法正常到達;

    所以一定要結合系統的一些性能觀察工具進行綜合分析,比如netstat統計單位時間的發送包的數量,看是否很明顯超過了所在網絡帶寬的限制;觀察CPU的利用率,看系統態的CPU時間是否明顯大於用戶態的CPU時間。這些都指向由於網絡帶寬所限導致的網絡瓶頸。

    1. 還有一種常見的情況是該線程在 sleep,等待 sleep 的時間到了,將被喚醒。
  • waiting for monitor entry 或 in Object.wait()

Moniter 是Java中用以實現線程之間的互斥與協作的主要手段,它可以看成是對象或者class的鎖,每個對象都有,也僅有一個 Monitor。

在這裏插入圖片描述
從上圖可以看出,每個Monitor在某個時刻只能被一個線程擁有,該線程就是 “Active Thread”,而其他線程都是 “Waiting Thread”,分別在兩個隊列 "Entry Set"和"Waint Set"裏面等待。其中在 “Entry Set” 中等待的線程狀態是 waiting for monitor entry,在 “Wait Set” 中等待的線程狀態是 in Object.wait()。

(1)"Entry Set"裏面的線程。
我們稱被 synchronized 保護起來的代碼段爲臨界區,對應的代碼如下:

synchronized(obj) { }COPY

當一個線程申請進入臨界區時,它就進入了 “Entry Set” 隊列中,這時候有兩種可能性:

該Monitor不被其他線程擁有,"Entry Set"裏面也沒有其他等待的線程。本線程即成爲相應類或者對象的Monitor的Owner,執行臨界區裏面的代碼;此時在Thread Dump中顯示線程處於 “Runnable” 狀態。

該Monitor被其他線程擁有,本線程在 “Entry Set” 隊列中等待。此時在Thread Dump中顯示線程處於 “waiting for monity entry” 狀態。

臨界區的設置是爲了保證其內部的代碼執行的原子性和完整性,但因爲臨界區在任何時間只允許線程串行通過,這和我們使用多線程的初衷是相反的。如果在多線程程序中大量使用synchronized,或者不適當的使用它,會造成大量線程在臨界區的入口等待,造成系統的性能大幅下降。如果在Thread Dump中發現這個情況,應該審視源碼並對其進行改進。

(2)"Wait Set"裏面的線程
當線程獲得了Monitor,進入了臨界區之後,如果發現線程繼續運行的條件沒有滿足,它則調用對象(通常是被synchronized的對象)的wait()方法,放棄Monitor,進入 "Wait Set"隊列。只有當別的線程在該對象上調用了 notify()或者notifyAll()方法,"Wait Set"隊列中的線程纔得到機會去競爭,但是隻有一個線程獲得對象的Monitor,恢復到運行態。"Wait Set"中的線程在Thread Dump中顯示的狀態爲 in Object.wait()。通常來說,

通常來說,當CPU很忙的時候關注 Runnable 狀態的線程,反之則關注 waiting for monitor entry 狀態的線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章