用代碼和圖告訴你VisualVM中的線程的幾種狀態

VisualVM是壓測過程中經常用到的一個工具,但是在分析過程中對其中的幾種狀態瞭解的不太清楚,通過查閱資源和代碼中測試,基本搞懂了這些狀態的區別。


狀態說明:

  • Running
    處於這種狀態的線程對於操作系統而言,要麼是正在佔用CPU時間片運行的線程,要麼是已經就緒的線程,只要有CPU時間片分配到,就可以直接運行,對應Java中Runnable狀態。

  • Sleeping
    處於睡眠狀態的線程,通過調用Thread.sleep()方法讓線程進行這種狀態,此種狀態的線程不佔用CPU,但是不釋放鎖資源。

  • Wait
    通過調用Object.wait()、Thread.join()等方法讓線程進入這種狀態,這種狀態的線程不僅會讓出CPU資源,也會讓出所佔用的鎖資源。

  • Park
    通過調用LockSupport類中的一些列park方法進行此種狀態。這種狀態是線程沒有佔用鎖,但是可以直接讓線程讓出CPU,其他的方法都提到了鎖的概念。

  • Monitor
    通過搶佔synchronized中的鎖而進入的狀態。

其實還有一些間接調用上述方法的鎖,也會進行提到的某種狀態,具體情況看看源碼分析下吧。

廢話少說,看看我的代碼如果先線程進入不同的狀態吧。
線程狀態
模擬代碼如下:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 *
 * visualvm中線程幾種狀態的模擬
 * 主要涉及到
 * Running: 運行態,此時正在使用CPU的時間片
 * Sleeping:休眠狀態,調用Thread.sleep(),不佔用CPU
 * Wait:調用Object.wait、Thread.join等方法會進入這個狀態
 * Park:調用LockSupport.park等方法會進入這個狀態,底層調用的是
 * Monitor:通過synchronized搶佔鎖
 **/
public class ThreadStateSimulateTest {

    public static void main(String[] args) {
        // 模擬sleeping, Thread.sleep()會使線程進入Sleeping狀態
        Thread t = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                }catch (InterruptedException e) {}
            }
        }, "simulateSleeping");
        t.start();
        // 調用Thread.join的線程會進入Wait狀態
        Thread t1 = new Thread(() -> {
            System.out.println("開始模擬wating");
            try {
                t.join();
            }catch (InterruptedException e) {}
        }, "simulateWaiting");
        t1.start();

        // LockSupport.park會讓線程進入park狀態(其實就是不涉及鎖的情況下,直接讓線程讓出cpu)
        Thread t2 = new Thread(() -> {
            System.out.println("park方法直接讓線程讓出cpu");
            LockSupport.park();
        }, "simulateParking");
        t2.start();

        Thread t3 = new Thread(() -> {
            say();
        }, "simulateMonitor1");

        Thread t4 = new Thread(() -> {
            say();
        }, "simulateMonitor2");
        t3.start();
        t4.start();

        Thread t5 = new Thread(() -> {
            while(true) {}
        }, "simulateRunning");
        t5.start();
    }

    public synchronized static void say() {
        while(true) {
            try {
                // 下面兩個操作都不會讓出synchronized佔用的鎖資源
                System.out.println("synchronized:" + Thread.currentThread());
                LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500));
                Thread.sleep(500);
            }catch (Exception e) {}
        }
    }


}

simulateSleeping線程調用了Thread.sleep(1000);這個方法,直接進入了Sleeping狀態。

simulateWaiting線程調用了t.join();這個方法進入了Wating狀態。

simulateParking調用了LockSupport.park();這個方法進入了Park狀態。

simulateRunning直接就是Running狀態的線程。

simulateMonitor1和simulateMonitor2線程配合使用,會導致先搶到鎖的進入一個循環,不釋放鎖,後來的一個線程只能阻塞等待,進入Monitor狀態。

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