JVirtualVM 中線程狀態(運行/休眠/等待/駐留/監視)解析


在java自帶的工具JVirtualVM中線程有以下幾種狀態:

先說結論,各狀態含義如下,后面有詳細的demo測試驗證:

  • 運行(runnable):正在運行中的線程。
  • 休眠(timed_waiting):休眠線程,例如調用Thread.sleep方法。
  • 等待(waiting):等待喚醒的線程,可通過調用Object.wait方法獲得這種狀態,底層實現是基於對象頭中的monitor對象
  • 駐留(waiting):等待喚醒的線程,和等待狀態類似,只不過底層的實現方式不同,處於這種狀態的例子有線程池中的空閑線程,等待獲取reentrantLock鎖的線程,調用了reentrantLock的condition的await方法的線程等等,底層實現是基於Unsafe類的park方法,在AQS中有大量的應用。
  • 監視(blocked):等待獲取monitor鎖的線程,例如等待進入synchronize代碼塊的線程。

代碼測試

    private static final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

    private static final ReentrantLock reentrantLockTest = new ReentrantLock();

    public static void main(String[] args) {

        //基於println方法中的synchronize代碼塊測試運行或者監視線程
        Thread thread1 = new Thread(() -> {
            while (true) {
                System.out.println("運行或者監視線程1");
            }
        }, "運行或者監視線程1");
        thread1.start();

        //基於println方法中的synchronize代碼塊測試運行或者監視線程
        Thread thread2 = new Thread(() -> {
            while (true) {
                System.out.println("運行或者監視線程2");
            }
        }, "運行或者監視線程2");
        thread2.start();

        //monitor對象等待線程
        Object lock = new Object();
        Thread thread3 = new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "等待線程synchronized");
        thread3.start();

        //reentrantLock中的條件對象調用await方法線程為駐留線程
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();
        Thread thread4 = new Thread(() -> {
            reentrantLock.lock();
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        }, "等待線程reentrantLock");
        thread4.start();

        //休眠線程
        Thread thread5 = new Thread(() -> {
            try {
                Thread.sleep(1000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "休眠線程");
        thread5.start();

        Thread thread6 = new Thread(ThreadTest::lockMethod, "reentrantLock運行線程");
        thread6.start();

        //等待獲取reentrantLock的線程為駐留線程
        Thread thread7 = new Thread(() -> {
            try {
                TimeUnit.MICROSECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lockMethod();
        }, "reentrantLock監視線程");
        thread7.start();

        //線程池中的空閑線程為駐留線程
        singleThreadExecutor.execute(() -> {
            //線程池中的線程是懶加載,需要運行任務之后才會產生線程
            System.out.println("駐留線程運行");
        });
    }

    private static void lockMethod() {
        reentrantLockTest.lock();
        try {
            while (true) {
            }
        } finally {
            reentrantLockTest.unlock();
        }
    }

	//println源碼也簡單貼一下
	//java.io.PrintStream#println(java.lang.String)
    public void println(String x) {
        //this表示System.out這個PrintStream對象
        synchronized (this) {
            print(x);
            newLine();
        }
    }  

以上代碼運行之后,打開JVirtualVM查看線程如下:

根據代碼的順序從上至下講:

  • 兩個運行或者監視線程的System.out.println()語句因為搶同一個synchronize鎖,可以很明顯的看出是在交替運行,狀態分別處於運行監視狀態。

  • 等待線程synchronize因為調用了Object的wait方法,一直處於等待狀態。

  • 休眠線程省略。

  • 重點是和reentrantLock鎖相關的三個線程,可以看到無論是通過condition的await方法,還是在阻塞等待鎖的過程中,都是處於駐留狀態,而不是我一開始預想的等待狀態,通過查看源碼后發現它們最終都調用了Unsafe的park方法,后續的線程dump也能驗證這一點。

  • pool- 1-threadpool-1就是那個線程池,因為里面的線程處於空閑狀態,也屬於駐留

線程dump


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM