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

Java 多執行緒實戰:棄用 Thread.stop/suspend/resume 及常見併發陷阱排查

     編輯:Java 相關知識

為什麼不應使用 stop()、suspend()、resume()?

這三個方法自 Java 1.2 起即被標記為 @Deprecated,主要原因在於它們會破壞執行緒安全機制,導致極難排查的微妙錯誤:

  • stop():強制釋放所有鎖,可能導致受保護資料處於不一致狀態,引發資料損壞。
  • suspend()/resume():極易造成死鎖。若被掛起的執行緒持有鎖,其他嘗試獲取該鎖的執行緒將永久阻塞,直到 resume() 被調用——但 resume() 若在 suspend() 之前調用,會導致執行緒永久掛起。

最佳實踐:使用 interrupt() 機制配合 volatile 標誌位或 Thread.interrupted() 檢查,實現優雅的執行緒終止與暫停/恢復邏輯。

多執行緒程式四大「噩夢」與應對策略

1. 死鎖

成因:多執行緒循環等待彼此持有的鎖(如執行緒 A 鎖 1 等鎖 2,執行緒 B 鎖 2 等鎖 1)。

預防鐵律:所有執行緒按固定全域順序獲取鎖。例如資源 A、B、C、D 必須按 A→B→C→D 順序加鎖,釋放順序相反。雖可能增加阻塞,但能從根本上杜絕死鎖。

2. 活鎖

現象:執行緒忙於應對外部事件(如不斷重試、禮讓),導致實際業務邏輯永無推進機會,最終耗盡資源崩潰。類比:秘書整天接電話,信從未打出。

對策:引入隨機退避、指數退避策略;使用公平鎖或信號量控制併發度;設計無鎖資料結構(如 ConcurrentHashMap、LongAdder)。

3. 記憶體損壞

本質:多執行緒非原子性操作共享可變狀態,導致資料競爭。

核心防線:synchronized / ReentrantLock 保護臨界區;volatile 保證可見性;Atomic* 類實現無鎖原子操作;ThreadLocal 實現執行緒隔離。

4. 資源耗盡

典型場景:資料庫連線、檔案描述符、執行緒本身屬有限資源,無限制創建必導致耗盡。

標準解法:資源池化。資料庫連線池、執行緒池、物件池均屬此類。核心邏輯:取用→使用→歸還,配合超時回收與監控告警。

實戰除錯利器:執行緒探針

當系統執行緒數量龐大、傳統除錯失效時,可部署一個守護執行緒定期掃描全量執行緒狀態:

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、建立鎖順序規範、善用併發工具包、引入資源池化、建立可觀測性體系。唯有敬畏併發複雜度,方能馴服多核時代的野馬。

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