一、 執行緒(Thread)的物理代價與本質
排程實體:在現代 HotSpot JVM 中,Java 的 Thread 採用 1:1 映射至作業系統原生核心執行緒(Kernel-Level Thread, KLT)。
資源開銷:
記憶體:每個 Java 執行緒預設分配獨立的呼叫棧空間(Thread Stack,預設約 1MB,由 -Xss 控制)。建立 1000 個執行緒即佔用約 1GB 記憶體。
CPU 成本:執行緒切換涉及作業系統核心態與使用者態(Kernel Mode vs User Mode)切換,以及 CPU 暫存器、程式計數器(PC Register)的上下文切換(Context Switch)開銷。
二、 JVM 定義的 Thread 六大生命週期狀態(Thread.State)
作業系統通常將行程分為五態(新建、就緒、運行、阻塞、終止),而 Java Thread.State 列舉定義了嚴格的六種狀態:
三、 synchronized 底層核心:ObjectMonitor 監視器機制synchronized 關鍵字並非純語法糖,它依賴 JVM 底層的 ObjectMonitor(物件監視器) 進行併發控制。
四、 死鎖(Deadlock)的四個必要條件與破局防禦當兩個或多個執行緒彼此互相持有對方需要的鎖、且都在等待對方釋放時,系統便陷入永久停滯。
1. 死鎖發生的四大必要條件(缺一不可):互斥條件(Mutual Exclusion):資源同一時間只能被一個執行緒佔有(鎖的本質)。持有並等待(Hold and Wait):執行緒已持有至少一個資源,但又發起請求爭奪已被其他執行緒佔有的新資源。不可剝奪(No Preemption):已獲取的資源在未主動釋放前,外部無法強行剝奪。循環等待(Circular Wait):存在一條執行緒與鎖的封閉環形鏈條(Thread A 拿著 Lock 1 等 Lock 2,Thread B 拿著 Lock 2 等 Lock 1)。
2. 架構預防死鎖的工程守則:破除循環等待(全域鎖排序,Lock Ordering):黃金法則:所有執行緒在請求多個鎖時,必須按照嚴格相同的順序獲取鎖。例如轉帳情境:比較兩個帳戶的 ID 大小,永遠先鎖 ID 較小的帳戶,再鎖 ID 較大的帳戶,徹底消除環形依賴。破除不可剝奪(改用顯式鎖 ReentrantLock):synchronized 無法被中斷且無法設定超時。改用 JUC 的 ReentrantLock.tryLock(timeout, unit):若在指定時間內拿不到鎖,主動放棄已持有的資源並退讓重試,破除僵局。排查死鎖工具:生產環境排查:使用 JDK 內建命令列工具 jstack ,工具會自動掃描執行緒棧並輸出 Found one Java-level deadlock 與對應代碼行號。