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

Java 多執行緒編程禁用 API 深度解析與併發問題診斷指南

     編輯:Java 相關知識

Java 早期版本提供的 Thread.stop()、suspend()、resume() 等方法因嚴重缺陷已被棄用。本文深度剖析棄用原因、併發常見問題模式、診斷工具與現代最佳實踐。

被棄用方法的致命缺陷

Thread.stop():破壞物件一致性

  • 強制釋放該執行緒持有的所有鎖,導致受保護物件處於不一致狀態
  • 其他執行緒可能讀取到「半更新」的物件,產生難以重現的資料競爭
  • 無法保證 finally 區塊執行,資源洩漏風險

Thread.suspend()/resume():死鎖製造者

  • suspend() 不釋放鎖,若目標執行緒持有鎖並嘗試獲取另一把鎖,而恢復執行緒需獲取該鎖 → 經典死鎖
  • 無法中斷 I/O 阻塞或鎖等待,響應性極差

現代替代方案:中斷機制與協作式取消

// 標準取消模式
public class CancellableTask implements Runnable {
    private volatile boolean cancelled = false;
    
    public void cancel() { cancelled = true; }
    
    @Override
    public void run() {
        while (!cancelled && !Thread.currentThread().isInterrupted()) {
            // 定期檢查中斷狀態
            if (Thread.interrupted()) break;
            doWork();
        }
        cleanup(); // 釋放資源
    }
}

// 使用方式
Thread t = new Thread(new CancellableTask());
t.start();
// 需要停止時
t.interrupt(); // 設置中斷標誌
// 或 task.cancel();

四大併發經典問題模式

1. 死鎖

條件:互斥、持有並等待、不可搶佔、循環等待

// 破壞循環等待:統一鎖獲取順序
// 所有執行緒按相同順序獲取鎖 A → B → C → D
synchronized(lockA) {
    synchronized(lockB) { ... }
}

工具:jstack 分析 BLOCKED 狀態執行緒、ThreadMXBean.findDeadlockedThreads() 程式化檢測

2. 活鎖

執行緒持續嘗試操作但因條件不滿足而重試,CPU 佔用高但無實質進展。類比:兩人走廊相遇反復避讓。

// 解決:引入隨機退避
while (!tryAcquire()) {
    Thread.sleep(random.nextInt(100)); // 指數退避更佳
}

3. 記憶體可見性問題

缺乏 volatile/synchronized/final 導致執行緒讀取到舊值。

// 錯誤:編譯器/JIT 可能優化為無限循環
while (!stop) { ... }

// 正確:volatile 保證可見性與有序性
private volatile boolean stop = false;

4. 資源耗盡

執行緒池耗盡、連線池耗盡、檔案描述符耗盡。

  • 配置有界佇列 + 拒絕策略
  • 監控指標:ThreadPoolExecutor.getQueue().size()、getActiveCount()
  • 資源池化:HikariCP (資料庫)、Apache HttpClient (HTTP 連線)

大量執行緒診斷工具類


public class ThreadProbe extends Thread {
    @Override
    public void run() {
        while (true) {
            Thread[] threads = new Thread[Thread.activeCount() * 2];
            int count = Thread.enumerate(threads);
            for (int i = 0; i < count; i++) {
                Thread t = threads[i];
                System.out.printf("%-30s %5d %5b %5b%n",
                    t.getName(), t.getPriority(), t.isAlive(), t.isDaemon());
            }
            try { Thread.sleep(5000); } catch (InterruptedException e) { break; }
        }
    }
}

生產環境建議使用 Arthas、Async Profiler、JConsole、VisualVM 進行無侵入式分析。

最佳實踐總結

  1. 永不使用 stop()、suspend()、resume()、destroy()
  2. 採用 中斷標誌 + volatile 協作式取消
  3. 鎖排序統一、鎖粒度最小化、優先使用 java.util.concurrent 組件
  4. 共享狀態必須 volatile 或同步,不可變物件優先
  5. 執行緒池預熱、監控、隔離(業務分組)
  6. 併發測試:壓測 + jcstress 驗證並發正確性

參考資源

  • 《Java Concurrency in Practice》- Goetz 等
  • JDK 文檔:Thread、ThreadPoolExecutor、CompletableFuture
  • Arthas 官網:https://arthas.aliyun.com/
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved