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

Java 多線程核心機制深度解析:啟動、暫停、結束、監聽與同步協作模式

     編輯:Java 綜合教學

線程啟動與入口:start() vs run()

必須調用 Thread.start() 啟動線程,這會創建新調用棧並異步執行 run()。直接調用 run() 只是普通方法調用,仍在主線程中同步執行。

Thread thread = new Thread(() -> {
    System.out.println("子線程運行:" + Thread.currentThread().getName());
});
thread.start(); // 正確啟動
// thread.run(); // 錯誤:主線程同步執行

Runnable vs Thread 設計模式

Thread與Runnable關系

  • 繼承 Thread:簡單,但單繼承限制,邏輯與線程控制耦合
  • 實現 Runnable:推薦,分離任務邏輯與線程管理,支持線程池、Lambda、多實例共享任務
  • 實現 Callable:有返回值、可拋異常,配合 Future/ExecutorService 使用

線程暫停與恢復:核心機制對比

暫停恢復機制

1. Thread.sleep(millis) - 定時休眠

  • 靜態方法,當前線程讓出 CPU,進入 TIMED_WAITING
  • 不釋放鎖(synchronized/ReentrantLock)
  • 可被 interrupt() 喚醒拋出 InterruptedException
  • 場景:定時輪詢、限流延遲、模擬耗時操作

2. Object.wait() / notify() - 協作等待

  • 實例方法,必須在 synchronized 同步塊中調用
  • wait() 釋放鎖,進入 WAITING,加入對象等待隊列
  • notify() 喚醒單個,notifyAll() 喚醒全部,重新競爭鎖
  • 場景:生產者消費者、狀態變更通知、屏障同步

3. LockSupport.park() / unpark() - 線程級阻塞

  • 不需要鎖,直接操作線程許可證
  • park() 消費許可證(無則阻塞),unpark() 發放許可證
  • 不拋出 InterruptedException,需自檢 Thread.interrupted()
  • JUC 同步器(AQS)、CompletableFuture 底層基石

4. Condition.await() / signal() - 精確控制

  • Lock.newCondition() 創建,綁定特定 Lock
  • 支持多條件隊列(如:不滿/不空隊列分離)
  • API 豐富:awaitNanos、awaitUntil、awaitUninterruptibly

線程結束與監聽:優雅關閉模式

自然結束

  • run() 方法正常返回
  • 異常拋出未捕獲導致線程死亡

強制中止(不推薦)

  • Thread.stop():已棄用,釋放所有鎖導致數據不一致
  • Thread.destroy():未實現,不可用

優雅停止標準模式:中斷標誌 + interrupt()

public class GracefulShutdownTask implements Runnable {
    private volatile boolean running = true;

    public void shutdown() { running = false; }

    @Override
    public void run() {
        while (running && !Thread.currentThread().isInterrupted()) {
            try {
                // 業務邏輯
                doWork();
                // 可中斷阻塞點
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 重置中斷狀態
                break; // 退出循環
            }
        }
        cleanup(); // 資源釋放
    }
}

守護線程:隨主線程退出而強制結束

Thread daemon = new Thread(() -> {
    while (true) { /* 後台任務 */ }
});
daemon.setDaemon(true); // 必須在 start() 前設置
daemon.start();
  • JVM 只有非守護線程時退出
  • 適用:心跳檢測、緩存清理、監控採集等非關鍵後台任務
  • 不適用:持久化操作、事務提交、關鍵資源釋放

線程監聽與協作實戰

1. join() 等待線程結束

Thread t = new Thread(() -> { /* 耗時任務 */ });
t.start();
t.join();           // 主線程阻塞,直到 t 結束
t.join(5000);       // 最多等待 5 秒

原理:join() 內部調用 this.wait(0),線程結束時 JVM 自動 this.notifyAll()。

2. 同步鎖監聽示例:主線程等待子線程完成

Thread thread = new Thread(() -> {
    try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
    System.out.println("子線程結束");
});
thread.start();
synchronized (thread) {
    thread.wait(); // 等待 thread 對象鎖被 notifyAll(線程結束時自動觸發)
}
System.out.println("主線程結束");

3. interrupt() 中斷阻塞線程

Thread[] threads = new Thread[5];
for (int i = 0; i < 5; i++) {
    final int num = i + 1;
    threads[i] = new Thread(() -> {
        synchronized (lock) {
            try { lock.wait(); } catch (InterruptedException e) { /* 被喚醒 */ }
            // 此處仍持有鎖,需退出同步塊才真正釋放
        }
    });
    threads[i].start();
}
// 2秒後中斷所有
Thread.sleep(2000);
for (Thread t : threads) t.interrupt();
for (Thread t : threads) t.join();

輸出驗證:中斷喚醒 → 執行同步塊後續代碼 → 退出同步塊 → 線程結束。

並發與並行:概念釐清

並行:多核 CPU 同一時刻執行多線程。並發:單核 CPU 時間片輪轉交替執行多線程,宏觀並行、微觀串行。Java 線程調度依賴操作系統,現代多核環境下並存並發與並行。

總結:線程控制最佳實踐

  1. 優先使用線程池:ExecutorService 管理生命週期、復用線程、控制併發度
  2. 任務邏輯與線程分離:實現 Runnable/Callable
  3. 優雅停止:volatile boolean 標誌 + interrupt() + 可中斷阻塞點處理
  4. 避免低級同步:優先用 JUC:CountDownLatch、CyclicBarrier、Semaphore、CompletableFuture、BlockingQueue
  5. 守護線程謹慎用:非關鍵、可丟失進度的後台任務
  6. 中斷是協作機制:被中斷方決定如何響應,不可強制

掌握線程啟動、暫停、結束、監聽的底層機制與高級 API,是編寫高併發、高可靠 Java 系統的核心功力。

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