Java 早期版本提供的 Thread.stop()、suspend()、resume() 等方法因嚴重缺陷已被棄用。本文深度剖析棄用原因、併發常見問題模式、診斷工具與現代最佳實踐。
finally 區塊執行,資源洩漏風險suspend() 不釋放鎖,若目標執行緒持有鎖並嘗試獲取另一把鎖,而恢復執行緒需獲取該鎖 → 經典死鎖// 標準取消模式
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();
條件:互斥、持有並等待、不可搶佔、循環等待
// 破壞循環等待:統一鎖獲取順序
// 所有執行緒按相同順序獲取鎖 A → B → C → D
synchronized(lockA) {
synchronized(lockB) { ... }
}
工具:jstack 分析 BLOCKED 狀態執行緒、ThreadMXBean.findDeadlockedThreads() 程式化檢測
執行緒持續嘗試操作但因條件不滿足而重試,CPU 佔用高但無實質進展。類比:兩人走廊相遇反復避讓。
// 解決:引入隨機退避
while (!tryAcquire()) {
Thread.sleep(random.nextInt(100)); // 指數退避更佳
}
缺乏 volatile/synchronized/final 導致執行緒讀取到舊值。
// 錯誤:編譯器/JIT 可能優化為無限循環
while (!stop) { ... }
// 正確:volatile 保證可見性與有序性
private volatile boolean stop = false;
執行緒池耗盡、連線池耗盡、檔案描述符耗盡。
ThreadPoolExecutor.getQueue().size()、getActiveCount()
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 進行無侵入式分析。
stop()、suspend()、resume()、destroy()java.util.concurrent 組件volatile 或同步,不可變物件優先jcstress 驗證並發正確性Thread、ThreadPoolExecutor、CompletableFuturehttps://arthas.aliyun.com/