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

Java 線程優雅停止:volatile 布爾標誌位模式深度解析

     編輯:Java 相關知識

為什麼不推薦 Thread.stop()?

stop() / suspend() / resume() 已棄用:強制釋放鎖導致數據不一致、對象處於破損狀態。正確做法是協作式停止——線程定期檢查標誌位,主動退出 run()。

標誌位模式標準範本

public class StoppableTask extends Thread {
    // volatile 保證跨線程可見性:主線程寫入,工作線程讀取
    private volatile boolean stopRequested = false;

    @Override public void run() {
        while (!stopRequested) {
            // 執行業務邏輯
            doWork();
            // 適當休眠降低 CPU 佔用
            sleepQuietly(720);
        }
        // 清理資源、釋放鎖、關閉連接
        cleanup();
        System.out.println("線程已優雅停止");
    }

    public void requestStop() { stopRequested = true; }

    private void doWork() { System.out.println("Working..."); }
    private void cleanup() { /* 關閉流、歸還連接池等 */ }
    private void sleepQuietly(long ms) {
        try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
    }

    public static void main(String[] args) throws InterruptedException {
        StoppableTask t = new StoppableTask();
        t.start();
        Thread.sleep(5000); // 讓它跑 5 秒
        t.requestStop();    // 發送停止信號
        t.join();           // 等待線程實際結束
        System.out.println("主線程結束");
    }
}

關鍵細節解析

細節原因代碼體現
volatile禁止指令重排、強制從主內存讀寫,保證主線程修改對工作線程立即可見private volatile boolean stopRequested
檢查點位置放在循環條件、耗時操作前後、I/O 等待後,確保「及時響應」while (!stopRequested)
處理 InterruptedException休眠/等待時被 interrupt() 喚醒,應重新設置中斷標誌或直接退出Thread.currentThread().interrupt();
資源清理退出循環後在 run() 末尾釋放鎖、關閉流、歸還連接池cleanup()
join() 等待主線程確認工作線程完全結束再繼續,避免殘留資源洩漏t.join()

進階:結合 interrupt() 雙重保障

public class HybridStoppableTask implements Runnable {
    private volatile boolean stop = false;

    @Override public void run() {
        while (!stop && !Thread.currentThread().isInterrupted()) {
            try {
                doWork();
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 重新設置標誌
                break; // 直接跳出
            }
        }
        cleanup();
    }

    public void shutdown() {
        stop = true;
        // 若線程阻塞在 sleep/wait/join,interrupt() 能喚醒它
        Thread.currentThread().interrupt(); // 注意:這裡需持有線程引用
    }
}

生產級替代:ExecutorService 生命週期管理

ExecutorService pool = Executors.newSingleThreadExecutor();
Future<?> future = pool.submit(new StoppableTask());

// ... 業務邏輯 ...
future.cancel(true); // true = mayInterruptIfRunning
pool.shutdown();
pool.awaitTermination(10, TimeUnit.SECONDS);
  • Future.cancel(true) 內部調用 thread.interrupt();
  • 配合 Thread.currentThread().isInterrupted() 檢查實現響應;
  • 統一管理線程池,避免手動 Thread 洩漏。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved