Java語言定義的線程狀態分析

    說到線程,必定要談到線程狀態,不一樣的狀態說明線程正處於不一樣的工做機制下,不一樣的工做機制下某些動做可能對線程產生不一樣的影響。html

    Java語言定義了6中狀態,而同一時刻,線程有且僅有其中的一種狀態。要獲取Java線程的狀態可使用 java.lang.Thread類中定義的 getState()方法,獲取當前線程的狀態就可使用Thread.currentThread().getState()來獲取。該方法返回的類型是一個枚舉類型,是Thread內部的一個枚舉,全稱爲「java.lang.Thread.State」,這個枚舉中定義的類型列表就是Java語言這個級別對應的線程狀態列表,包含了NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED這些值。java

 

如下是本文的目錄大綱:算法

1、Java的幾種線程狀態說明apache

2、Java線程狀態轉換圖tomcat

3、「VisualVM線程監控線程狀態」與「Java線程狀態」對應關係網絡

 

如有不正之處請多多諒解,歡迎批評指正、互相討論。app

請尊重做者勞動成果,轉載請標明原文連接:dom

http://www.cnblogs.com/trust-freedom/p/6606594.htmlsocket

 

1、Java的幾種線程狀態說明

一、NEW(新建)ui

java.lang.Thread.State枚舉中的NEW狀態描述:

/**
 * Thread state for a thread which has not yet started.
 */
NEW

建立後還沒有啓動的線程處於這個狀態。

意思是這個線程沒有被start()啓動,或者說還根本不是一個真正意義上的線程,從本質上講這只是建立了一個Java外殼,尚未真正的線程來運行。

不表明調用了start(),狀態就當即改變,中間還有一些步驟,若是在這個啓動的過程當中有另外一個線程來獲取它的狀態,實際上是不肯定的,要看那些中間步驟是否已經完成了。

二、RUNNABLE(可運行)

java.lang.Thread.State枚舉中的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

RUNNABLE狀態包括了操做系統線程狀態中的Running和Ready,也就是處於此狀態的線程可能正在運行,也可能正在等待系統資源,如等待CPU爲它分配時間片,如等待網絡IO讀取數據。

RUNNABLE狀態也能夠理解爲存活着正在嘗試徵用CPU的線程(有可能這個瞬間並無佔用CPU,可是它可能正在發送指令等待系統調度)。因爲在真正的系統中,並非開啓一個線程後,CPU就只爲這一個線程服務,它必須使用許多調度算法來達到某種平衡,不過這個時候線程依然處於RUNNABLE狀態。

三、BLOCKED(阻塞)

java.lang.Thread.State枚舉中的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
 * {@link Object#wait() Object.wait}.
 * 當一個線程要進入synchronized語句塊/方法時,若是沒有獲取到鎖,會變成BLOCKED
 * 或者在調用Object.wait()後,被notify()喚醒,再次進入synchronized語句塊/方法時,若是沒有獲取到鎖,會變成BLOCKED
 */
BLOCKED

BLOCKED稱爲阻塞狀態,或者說線程已經被掛起,它「睡着」了,緣由一般是它在等待一個「鎖」,當嘗試進入一個synchronized語句塊/方法時,鎖已經被其它線程佔有,就會被阻塞,直到另外一個線程走完臨界區或發生了相應鎖對象的wait()操做後,它纔有機會去爭奪進入臨界區的權利

在Java代碼中,須要考慮synchronized的粒度問題,不然一個線程長時間佔用鎖,其它爭搶鎖的線程會一直阻塞,直到擁有鎖的線程釋放鎖

處於BLOCKED狀態的線程,即便對其調用 thread.interrupt()也沒法改變其阻塞狀態,由於interrupt()方法只是設置線程的中斷狀態,即作一個標記,不能喚醒處於阻塞狀態的線程

注意:ReentrantLock.lock()操做後進入的是WAITING狀態,其內部調用的是LockSupport.park()方法

四、WAITING(無限期等待)

/**
 * Thread state for a waiting thread.
 * A thread is in the waiting state due to calling one of the
 * following methods:
 * <ul>
 *   <li>{@link Object#wait() Object.wait} with no timeout</li>
 *   <li>{@link #join() Thread.join} with no timeout</li>
 *   <li>{@link LockSupport#park() LockSupport.park}</li>
 * </ul>
 *
 * <p>A thread in the waiting state is waiting for another thread to
 * perform a particular action.
 *
 * For example, a thread that has called <tt>Object.wait()</tt>
 * on an object is waiting for another thread to call
 * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
 * that object. A thread that has called <tt>Thread.join()</tt>
 * is waiting for a specified thread to terminate.
 */
WAITING

處於這種狀態的線程不會被分配CPU執行時間,它們要等待顯示的被其它線程喚醒。這種狀態一般是指一個線程擁有對象鎖後進入到相應的代碼區域後,調用相應的「鎖對象」的wait()方法操做後產生的一種結果。變相的實現還有LockSupport.park()、Thread.join()等,它們也是在等待另外一個事件的發生,也就是描述了等待的意思。

如下方法會讓線程陷入無限期等待狀態:

(1)沒有設置timeout參數的Object.wait()

(2)沒有設置timeout參數的Thread.join()

(3)LockSupport.park()

注意:

LockSupport.park(Object blocker) 會掛起當前線程,參數blocker是用於設置當前線程的「volatile Object parkBlocker 成員變量」

parkBlocker 是用於記錄線程是被誰阻塞的,能夠經過LockSupport.getBlocker()獲取到阻塞的對象,用於監控和分析線程用的。

 

「阻塞」與「等待」的區別:

(1)「阻塞」狀態是等待着獲取到一個排他鎖,進入「阻塞」狀態都是被動的,離開「阻塞」狀態是由於其它線程釋放了鎖,不阻塞了;

(2)「等待」狀態是在等待一段時間 或者 喚醒動做的發生,進入「等待」狀態是主動的

如主動調用Object.wait(),如沒法獲取到ReentraantLock,主動調用LockSupport.park(),如主線程主動調用 subThread.join(),讓主線程等待子線程執行完畢再執行

離開「等待」狀態是由於其它線程發生了喚醒動做或者到達了等待時間

五、TIMED_WAITING(限期等待)

/**
 * Thread state for a waiting thread with a specified waiting time.
 * A thread is in the timed waiting state due to calling one of
 * the following methods with a specified positive waiting time:
 * <ul>
 *   <li>{@link #sleep Thread.sleep}</li>
 *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
 *   <li>{@link #join(long) Thread.join} with timeout</li>
 *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
 *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
 * </ul>
 */
TIMED_WAITING

處於這種狀態的線程也不會被分配CPU執行時間,不過無需等待被其它線程顯示的喚醒,在必定時間以後它們會由系統自動的喚醒。

如下方法會讓線程進入TIMED_WAITING限期等待狀態:

(1)Thread.sleep()方法

(2)設置了timeout參數的Object.wait()方法

(3)設置了timeout參數的Thread.join()方法

(4)LockSupport.parkNanos()方法

(5)LockSupport.parkUntil()方法

六、TERMINATED(結束)

/**
 * Thread state for a terminated thread.
 * The thread has completed execution.
 */
TERMINATED

已終止線程的線程狀態,線程已經結束執行。換句話說,run()方法走完了,線程就處於這種狀態。其實這只是Java語言級別的一種狀態,在操做系統內部可能已經註銷了相應的線程,或者將它複用給其餘須要使用線程的請求,而在Java語言級別只是經過Java代碼看到的線程狀態而已。

 

2、Java線程狀態轉換圖

 

上圖爲我的瞭解的線程狀態轉換的各類狀況,若有不到位的地方歡迎交流指教。

 

3、「VisualVM線程監控線程狀態」與「Java線程狀態」對應關係

經過VisualVM監控JVM時,能夠經過「線程」標籤頁查看JVM的線程信息,VisualVM的線程狀態以下:

經過dump thread stack,並與VisualVM監控信息中的線程名稱對應,找到的VisualVM每種線程狀態的線程堆棧以下:(請關注重點信息)

一、運行

"http-bio-8080-Acceptor-0" daemon prio=6 tid=0x000000000d7b4800 nid=0xa264 runnable [0x000000001197e000]
      java.lang.Thread.State: RUNNABLE
            at java.net.DualStackPlainSocketImpl.accept0(Native Method)
            at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
            at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
            at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
            - locked <0x00000000c2303850> (a java.net.SocksSocketImpl)
            at java.net.ServerSocket.implAccept(ServerSocket.java:530)
            at java.net.ServerSocket.accept(ServerSocket.java:498)
            at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:60)
            at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:220)
            at java.lang.Thread.run(Thread.java:745)

Locked ownable synchronizers:
        - None

二、休眠

"Druid-ConnectionPool-Destory-293325558" daemon prio=6 tid=0x000000000d7ad000 nid=0x9c94 waiting on condition [0x000000000bf0f000]
      java.lang.Thread.State: TIMED_WAITING (sleeping)
           at java.lang.Thread.sleep(Native Method)
            at com.alibaba.druid.pool.DruidDataSource$DestroyConnectionThread.run(DruidDataSource.java:1685)

Locked ownable synchronizers:
        - None

三、等待

"Finalizer" daemon prio=8 tid=0x0000000009349000 nid=0xa470 in Object.wait() [0x000000000a82f000]
      java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on <0x00000000c22a0108> (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)

      - locked <0x00000000c22a0108> (a java.lang.ref.ReferenceQueue.Lock)
            at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
            at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
        - None

 

"JMX server connection timeout 45" daemon prio=6 tid=0x000000000e846000 nid=0xab10 in Object.wait() [0x00000000137df000]
      java.lang.Thread.State: TIMED_WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
           - waiting on <0x00000000c55da3f0> (a [I)
            at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
            - locked <0x00000000c55da3f0> (a [I)
            at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
         - None

四、駐留

"http-bio-8080-exec-2" daemon prio=6 tid=0x000000000d7b8000 nid=0x9264 waiting on condition [0x000000000ee4e000]
      java.lang.Thread.State: WAITING (parking)
            at sun.misc.Unsafe.park(Native Method)
           - parking to wait for  <0x00000000c5629bc8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject)
            at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
            at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
            at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104)
            at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32)
            at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
            at java.util.concurrent.ThreadPoolExecutor.Worker.run(ThreadPoolExecutor.java:615)
            at org.apache.tomcat.util.threads.TaskThread.WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
        - None


"pool-9-thread-1" prio=6 tid=0x000000000d7b2000 nid=0xd5fc waiting on condition [0x000000001187e000]
       java.lang.Thread.State: TIMED_WAITING (parking)
             at sun.misc.Unsafe.park(Native Method)
             - parking to wait for  <0x00000000c563b9e0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject)
             at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
             at java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2082)
             at java.util.concurrent.ScheduledThreadPoolExecutor.DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1090)
             at java.util.concurrent.ScheduledThreadPoolExecutor.DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
             at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
             at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
             at java.util.concurrent.ThreadPoolExecutor.Worker.run(ThreadPoolExecutor.java:615)
             at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
       - None

五、監視

"Thread-1" prio=6 tid=0x000000000a8a1800 nid=0xfdb4 waiting for monitor entry [0x000000000b4de000]
      java.lang.Thread.State: BLOCKED (on object monitor)
            at com.jy.modules.test.Test2$T.run(Test2.java:58)
           - waiting to lock <0x00000000eab757e0> (a java.lang.Object)

Locked ownable synchronizers:
      - None

 

「VisualVM線程監控線程狀態」與「Java線程狀態」對應關係總結:

能夠看出,VisualVM的線程狀態將「WAITING」和「TIMED_WAITING」兩個狀態根據行程狀態的緣由作了細化(其實java的thread stack dump上已經細化了)

如形成「TIMED_WAITING」狀態的緣由多是 :

Thread.sleep()  --  休眠

Object.wait(timeout)  --  等待

LockSupport.parkUntil(deadline)  --  駐留

 

參考資料:

《深刻理解Java虛擬機》

《Java特種兵》5.1 基礎介紹

相關文章
相關標籤/搜索