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

Java 多線程核心問題剖析:死鎖成因與排查、線程優先級實戰指南

     編輯:Java 相關知識

一、死鎖:多線程編程的頭號殺手

定義與比喻

兩個或多個線程互相持有對方需要的鎖,並等待對方釋放,導致無限阻塞。如兩人禮讓進廁所,誰也不先進。

經典代碼復現

public class DeadlockDemo {
    private static final Object LOCK_A = new Object();
    private static final Object LOCK_B = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (LOCK_A) {
                sleep(100);
                synchronized (LOCK_B) { System.out.println("T1 獲得雙鎖"); }
            }
        }, "Thread-1");

        Thread t2 = new Thread(() -> {
            synchronized (LOCK_B) {
                sleep(100);
                synchronized (LOCK_A) { System.out.println("T2 獲得雙鎖"); }
            }
        }, "Thread-2");

        t1.start(); t2.start();
    }
    static void sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException ignored) {} }
}

輸出卡住,無任何後續日誌 —— 死鎖發生。

排查工具鏈

  1. jstack :線程堆棧快照,直接顯示 Found one Java-level deadlock 及鎖鏈。
  2. JVisualVM / JConsole:圖形化檢測死鎖,點擊「檢測死鎖」按鈕。
  3. Arthas:thread -b 一鍵定位阻塞線程與鎖持有者。
  4. 日誌/監控:CPU 佔用驟降、吞吐為 0、線程狀態長期 BLOCKED。

預防原則

  • 固定鎖獲取順序:全局規定獲取鎖的順序(如按 hashCode、名稱、ID 排序)。
  • 縮小同步塊:只同步必要代碼,減少持鎖時間。
  • 使用 Lock 接口:ReentrantLock.tryLock(timeout) 避免無限等待。
  • 避免嵌套鎖:重構設計,消除多鎖依賴。
  • 超時機制:數據庫鎖、分佈式鎖必須設置超時自動釋放。

二、線程優先級:理解與謹慎使用

三個標準優先級常量

  • Thread.MIN_PRIORITY = 1
  • Thread.NORM_PRIORITY = 5(默認)
  • Thread.MAX_PRIORITY = 10

設置方式

Thread t = new Thread(task);
t.setPriority(Thread.MAX_PRIORITY); // 必須在 start() 前設置
t.start();

運行演示

public class PriorityDemo {
    static class Printer extends Thread {
        public Printer(String name) { super(name); }
        @Override public void run() {
            for (int i = 0; i < 5; i++) System.out.println(getName() + ": " + i);
        }
    }
    public static void main(String[] args) {
        Thread high = new Printer("高優先級");
        Thread norm = new Printer("普通優先級");
        Thread low  = new Printer("低優先級");
        high.setPriority(Thread.MAX_PRIORITY);
        norm.setPriority(Thread.NORM_PRIORITY);
        low.setPriority(Thread.MIN_PRIORITY);
        high.start(); norm.start(); low.start();
    }
}

輸出中高優先級線程獲得更多 CPU 時間片,但不保證執行順序,受 OS 調度器影響大。

關鍵認知與避坑

誤區事實
高優先級線程一定先跑完優先級只影響調度概率,非決定性;I/O、鎖、睡眠會打斷
用優先級解決業務邏輯順序錯誤!業務順序靠同步機制(CountDownLatch、Future、信號量)保證
大量設置高優先級提升性能會導致餓死、系統線程(GC、JIT)被擠佔,反而降低整體吞吐
跨平台行為一致Windows/Linux/Solaris 對優先級映射不同,表現差異大

最佳實踐

  1. 默認使用 NORM_PRIORITY,極少手動調整。
  2. 真正需要響應性的極少數線程(如心跳檢測、實時采集)可適度提升。
  3. 後台批量任務、日誌刷盤、緩存清理可降至 MIN_PRIORITY。
  4. 優先用 線程池 + 任務隊列優先級(PriorityBlockingQueue)控制任務執行順序,而非線程優先級。

總結

死鎖是設計缺陷,通過固定鎖序、縮小同步範圍、超時機制從根源消除;線程優先級是調度提示而非控制指令,濫用反而有害。多線程核心能力在於正確同步、無鎖編程、線程池隔離、可觀測性建設,而非花哨的優先級技巧。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved