首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 併發編程實戰(二):線程屬性管理與狀態監控實戰

     編輯:Java 相關知識

Thread 核心屬性速覽

屬性獲取方法設置方法說明
IDgetId()不可設置JVM 分配的唯一長整型標識
NamegetName()setName()默認 "Thread-N",強烈建議業務語義命名
PrioritygetPriority()setPriority(1-10)1=MIN, 5=NORM, 10=MAX,**僅提示調度器,不保證**
StategetState()不可設置六大狀態:NEW/RUNNABLE/BLOCKED/WAITING/TIMED_WAITING/TERMINATED
DaemonisDaemon()setDaemon(true)守護線程:JVM 退出時不等待,必須在 start() 前設置
ThreadGroupgetThreadGroup()構造時指定線程組管理,現已較少使用

實戰:啟動 10 條線程,設置名稱/優先級,文件記錄狀態變遷

public class ThreadMonitorDemo {
    private static final Logger LOG = LoggerFactory.getLogger(ThreadMonitorDemo.class);

    public static void main(String[] args) throws IOException {
        int n = 10;
        Thread[] threads = new Thread[n];
        Thread.State[] lastStates = new Thread.State[n];

        // 1. 創建並配置線程
        for (int i = 0; i < n; i++) {
            final int num = i;
            Runnable task = () -> {
                for (int j = 0; j < 10; j++) {
                    System.out.printf("%s: %d * %d = %d%n",
                            Thread.currentThread().getName(), num, j, num * j);
                }
            };
            threads[i] = new Thread(task, "Worker-" + i);
            // 奇數高優先級,偶數低優先級
            threads[i].setPriority(i % 2 == 0 ? Thread.MAX_PRIORITY : Thread.MIN_PRIORITY);
            lastStates[i] = threads[i].getState(); // NEW
        }

        // 2. 記錄初始狀態
        try (PrintWriter pw = new PrintWriter(new FileWriter("thread-state.log"))) {
            for (int i = 0; i < n; i++) {
                pw.printf("MAIN: Thread[%d] %s INIT_STATE=%s%n", i, threads[i].getName(), lastStates[i]);
            }

            // 3. 批量啟動
            for (Thread t : threads) t.start();

            // 4. 輪詢監控狀態變化(生產環境建議用 JMX/Actuator)
            boolean allTerminated = false;
            while (!allTerminated) {
                allTerminated = true;
                for (int i = 0; i < n; i++) {
                    Thread.State current = threads[i].getState();
                    if (current != lastStates[i]) {
                        pw.printf("MAIN: Thread[%d] %s STATE_CHANGE: %s -> %s%n",
                                i, threads[i].getName(), lastStates[i], current);
                        lastStates[i] = current;
                    }
                    if (current != Thread.State.TERMINATED) allTerminated = false;
                }
                // 避免忙等佔用 CPU,實際可用 LockSupport.parkNanos(10_000_000)
                Thread.sleep(10); 
            }
            pw.println("MAIN: All threads terminated.");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

輸出日誌片段解讀


MAIN: Thread[0] Worker-0 INIT_STATE=NEW
MAIN: Thread[1] Worker-1 INIT_STATE=NEW
...
MAIN: Thread[0] Worker-0 STATE_CHANGE: NEW -> RUNNABLE
MAIN: Thread[2] Worker-2 STATE_CHANGE: NEW -> RUNNABLE
...
MAIN: Thread[0] Worker-0 STATE_CHANGE: RUNNABLE -> TERMINATED
MAIN: Thread[2] Worker-2 STATE_CHANGE: RUNNABLE -> TERMINATED
...
MAIN: All threads terminated.

觀察現象:高優先級線程(Worker-0,2,4...)傾向於更早進入 TERMINATED,但不保證絕對順序,受操作系統調度器影響。

生產級監控方案:不再手寫輪詢

  • JMX / Java Flight Recorder (JFR):JVM 內建,零代碼侵入,可導出 .jfr 分析火焰圖;
  • Spring Boot Actuator + Micrometer:/actuator/metrics/jvm.threads.states 直接暴露各狀態計數;
  • Arthas / Async Profiler:線上診斷神器,thread -n 10 實時查看前 10 忙碌線程堆棧;
  • ThreadMXBean:程序化獲取 CPU 時間、堆棧、死鎖檢測 findDeadlockedThreads()。

優先級陷阱與最佳實踐

⚠️ 警告:Thread.setPriority() 只是向操作系統調度器的提示,不保證執行順序。過度依賴優先級會導致:

  • 饑餓:低優先級線程長期得不到 CPU;
  • 優先級反轉:高優先級等待低優先級持有的鎖;
  • 跨平台行為差異:Windows/Linux 對優先級映射不同。

建議:業務代碼保持默認優先級 (NORM_PRIORITY);真正需要調度控制時,使用 線程池隔離(不同業務用不同線程池)、信號量/鎖公平性、CompletableFuture 優先級隊列 等結構化手段。

總結

  1. 線程命名規範:biz-module-action-index,如 order-pay-callback-3,便於日誌/Arthas 定位;
  2. 狀態監控生產環境用 JMX/Actuator,勿手寫輪詢;
  3. 優先級不作為核心調度手段,線程池隔離才是正道。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved