這三個方法自 Java 1.2 起即被標記為 @Deprecated,主要原因在於它們會破壞執行緒安全機制,導致極難排查的微妙錯誤:
最佳實踐:使用 interrupt() 機制配合 volatile 標誌位或 Thread.interrupted() 檢查,實現優雅的執行緒終止與暫停/恢復邏輯。
成因:多執行緒循環等待彼此持有的鎖(如執行緒 A 鎖 1 等鎖 2,執行緒 B 鎖 2 等鎖 1)。
預防鐵律:所有執行緒按固定全域順序獲取鎖。例如資源 A、B、C、D 必須按 A→B→C→D 順序加鎖,釋放順序相反。雖可能增加阻塞,但能從根本上杜絕死鎖。
現象:執行緒忙於應對外部事件(如不斷重試、禮讓),導致實際業務邏輯永無推進機會,最終耗盡資源崩潰。類比:秘書整天接電話,信從未打出。
對策:引入隨機退避、指數退避策略;使用公平鎖或信號量控制併發度;設計無鎖資料結構(如 ConcurrentHashMap、LongAdder)。
本質:多執行緒非原子性操作共享可變狀態,導致資料競爭。
核心防線:synchronized / ReentrantLock 保護臨界區;volatile 保證可見性;Atomic* 類實現無鎖原子操作;ThreadLocal 實現執行緒隔離。
典型場景:資料庫連線、檔案描述符、執行緒本身屬有限資源,無限制創建必導致耗盡。
標準解法:資源池化。資料庫連線池、執行緒池、物件池均屬此類。核心邏輯:取用→使用→歸還,配合超時回收與監控告警。
當系統執行緒數量龐大、傳統除錯失效時,可部署一個守護執行緒定期掃描全量執行緒狀態:
public class Probe extends Thread {
public void run() {
while (true) {
Thread[] threads = new Thread[100];
int count = Thread.enumerate(threads);
for (int i = 0; i < count; i++) {
Thread t = threads[i];
System.out.printf("%s\t%d\t%b\t%b%n",
t.getName(), t.getPriority(), t.isAlive(), t.isDaemon());
}
try { Thread.sleep(5000); } catch (InterruptedException ignored) {}
}
}
}
輸出包含執行緒名、優先級、存活狀態、守護執行緒標記,配合 jstack、VisualVM、Arthas 等專業工具,可快速定位死鎖、CPU 熱點、執行緒洩漏等疑難雜症。
Java 多執行緒編程的核心不在於 API 調用,而在於對併發模型的深度理解與工程化落地:拒絕棄用 API、建立鎖順序規範、善用併發工具包、引入資源池化、建立可觀測性體系。唯有敬畏併發複雜度,方能馴服多核時代的野馬。