Java 線程狀態之 blocked 和 waiting 的區別

一、引子

synchronized 會阻塞線程,AQS 也會阻塞線程。那麼這兩種情況,阻塞後,線程的狀態是什麼,是 waiting 還是 blocked。雖然好像知道,但不能確定。在網上搜索後,經過指引,找到 Thread.State 這個內部枚舉類型。

    /**
     * A thread state.  A thread can be in one of the following states:
     * <ul>
     * <li>{@link #NEW}<br>
     *     A thread that has not yet started is in this state.
     *     </li>
     * <li>{@link #RUNNABLE}<br>
     *     A thread executing in the Java virtual machine is in this state.
     *     </li>
     * <li>{@link #BLOCKED}<br>
     *     A thread that is blocked waiting for a monitor lock
     *     is in this state.
     *     </li>
     * <li>{@link #WAITING}<br>
     *     A thread that is waiting indefinitely for another thread to
     *     perform a particular action is in this state.
     *     </li>
     * <li>{@link #TIMED_WAITING}<br>
     *     A thread that is waiting for another thread to perform an action
     *     for up to a specified waiting time is in this state.
     *     </li>
     * <li>{@link #TERMINATED}<br>
     *     A thread that has exited is in this state.
     *     </li>
     * </ul>
     *
     * <p>
     * A thread can be in only one state at a given point in time.
     * These states are virtual machine states which do not reflect
     * any operating system thread states.
     *
     * @since   1.5
     * @see #getState
     */
    public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * 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,

        /**
         * 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}.
         */
        BLOCKED,

        /**
         * 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,

        /**
         * 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,

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

註釋已經寫的很清楚了。

重點來看 WAITING 和 BLOCKED 這兩種狀態。

二、BLOCKED

A thread that is blocked waiting for a monitor lock is in this state.

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() Object.wait.

這樣看來,blocked 狀態僅與 synchronized 關鍵字引起線程阻塞有關。

三、WAITING

A thread that is waiting indefinitely for another thread to perform a particular action is in this state.

Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:

  • Object#wait() Object.wait with no timeout
  • #join() Thread.join with no timeout
  • LockSupport#park() LockSupport.park

A thread in the waiting state is waiting for another thread to perform a particular action.

For example, 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. A thread that has called Thread.join() is waiting for a specified thread to terminate.

我們知道,AQS 內部就是依賴 LockSupport.park 阻塞線程,所以在 AQS 中被阻塞的線程處於 waiting 狀態。

四、總結

blocked 和 waiting 是 Java 線程的兩種阻塞狀態。
因爲爭用 synchronized 的 monitor 對象而發生阻塞的線程處於 blocked 狀態。
而 AQS 中的阻塞線程處於 waiting 狀態。

兩種狀態的區別:
兩種狀態對應的場景的區別,源碼中的註釋已經講的很清楚了。

但既然都是阻塞,還要分成這兩種,除了場景不同外,肯定還有底層更深層次的原因。
個人認爲更加本質的區別是,blocked 狀態指的是進行系統調用,通過操作系統掛起線程後,線程的狀態。而 waiting 狀態則不需要進行系統調用,是一種 JVM 層面的線程阻塞後的狀態。由於轉換到 blocked 狀態需要進行系統調用,所以到這個狀態的轉換操作比較重。

至於系統調用爲什麼比較重,可以參考 爲什麼系統調用比普通的函數調用更耗時?用戶態和內核態切換的代價在哪?

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