執行緒優先級與死鎖是併發編程中兩個既基礎又極易踩坑的主題。本文深入剖析優先級調度的真實行為、死鎖形成的四個必要條件、經典死鎖代碼示範,並提供工程級避免與排查策略。
Thread.MIN_PRIORITY = 1
Thread.NORM_PRIORITY = 5 (預設)
Thread.MAX_PRIORITY = 10
thread.setPriority(Thread.MAX_PRIORITY);
thread.getPriority();
MIN_PRIORITY。MAX_PRIORITY。NORM_PRIORITY,避免優先級反轉。**破壞任一條件即可避免死鎖**。
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) {
log("T1 持有 A,等待 B...");
sleep(1000); // 增加死鎖機率
synchronized (LOCK_B) { log("T1 獲得 B"); }
}
}, "T1");
Thread t2 = new Thread(() -> {
synchronized (LOCK_B) {
log("T2 持有 B,等待 A...");
sleep(1000);
synchronized (LOCK_A) { log("T2 獲得 A"); }
}
}, "T2");
t1.start(); t2.start();
}
static void log(String msg) { System.out.println(Thread.currentThread().getName() + ": " + msg); }
static void sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }
}
T1: T1 持有 A,等待 B...
T2: T2 持有 B,等待 A...
"T1" waiting for <0x000000076b2c1b68> (a java.lang.Object) // LOCK_B
- waiting to lock <0x000000076b2c1b68>
- locked <0x000000076b2c1b58> (a java.lang.Object) // LOCK_A
"T2" waiting for <0x000000076b2c1b58> (a java.lang.Object) // LOCK_A
- waiting to lock <0x000000076b2c1b58>
- locked <0x000000076b2c1b68> (a java.lang.Object) // LOCK_B
// 所有執行緒按相同順序獲取鎖:hashCode 比較或業務 ID 排序
public void transfer(Account from, Account to, int amt) {
Object first = from.hashCode() < to.hashCode() ? from : to;
Object second = first == from ? to : from;
synchronized (first) {
synchronized (second) { /* 轉帳邏輯 */ }
}
}
Lock lockA = new ReentrantLock();
Lock lockB = new ReentrantLock();
boolean gotA = lockA.tryLock(1, TimeUnit.SECONDS);
if (gotA) {
try {
boolean gotB = lockB.tryLock(1, TimeUnit.SECONDS);
if (gotB) { try { /* 安全區 */ } finally { lockB.unlock(); } }
else { log.warn("獲取 B 超時,釋放 A"); }
} finally { lockA.unlock(); }
}
ConcurrentHashMap, AtomicLong, LongAdder 替代 synchronized。若必須多鎖,統一用 Lock 並按順序 lock(),或用 Lock.tryLock() 全獲取或全放棄。
jstack / jcmd Thread.print :產生 Thread Dump,搜尋 BLOCKED、waiting for、locked。VisualVM / JConsole / Arthas:圖形化分析鎖依賴圖。-XX:+PrintConcurrentLocks:JVM 參數輸出 ReentrantLock 持有者資訊。ThreadMXBean.findDeadlockedThreads() 程式化偵測,可整合至健康檢查端點。| 現象 | 描述 | 典型原因 |
|---|---|---|
| 活鎖 | 執行緒非阻塞但無法推進(互相禮讓) | 過度禮讓邏輯、CAS 重試風暴 |
| 飢餓 | 低優先級/公平鎖下執行緒長期得不到 CPU/鎖 | 高優先級獨佔、非公平鎖持續搶佔 |
優先級只是調度提示,死鎖源於無序鎖獲取。**固定鎖順序、tryLock 超時、縮小同步範圍、優先用並發容器**是避免死鎖的四大鐵律。上線前必做壓測 + Thread Dump 分析,將死鎖風險消滅在萌芽狀態。