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

Java 並發編程基石:線程創建、守護線程與異常處理全解析

     編輯:Java 綜合教學

線程基本機制

  • 進程包含多個線程,共享堆/方法區,私有棧/程序計數器
  • 單核通過時間片輪轉實現併發,多核實現真並行
  • 阻塞(I/O、鎖、睡眠)釋放 CPU,提升整體吞吐

四種創建線程方式

1. 實現 Runnable 接口(推薦基礎方式)

public class LiftOff implements Runnable {
    private int countDown = 10;
    @Override public void run() {
        while (countDown-- > 0) {
            System.out.println(Thread.currentThread() + " #" + countDown);
            Thread.yield(); // 讓出 CPU,非強制
        }
    }
}
// 啟動
new Thread(new LiftOff()).start();

2. 繼承 Thread 類(不推薦,單繼承限制)

public class SimpleThread extends Thread {
    private int countDown = 5;
    public SimpleThread() { super(String.valueOf(++threadCount)); start(); }
    @Override public void run() {
        while (true) { System.out.println(this); if (--countDown == 0) return; }
    }
}

3. 提交給 ExecutorService(生產環境首選)

ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) exec.execute(new LiftOff());
exec.shutdown(); // 優雅關閉

// 其他線程池
Executors.newFixedThreadPool(n);     // 固定大小
Executors.newSingleThreadExecutor(); // 單線程串行
Executors.newScheduledThreadPool(n); // 定時/周期任務

4. 實現 Callable 接口(需返回值/拋異常)

class TaskWithResult implements Callable {
    private int id;
    public TaskWithResult(int id) { this.id = id; }
    @Override public String call() { return "result of " + id; }
}

ExecutorService exec = Executors.newCachedThreadPool();
List> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) futures.add(exec.submit(new TaskWithResult(i)));
for (Future f : futures) {
    try { System.out.println(f.get()); } // 阻塞獲取結果
    catch (Exception e) { e.printStackTrace(); }
}
exec.shutdown();

守護線程

  • 後台服務線程(GC、JIT 編譯),優先級極低
  • thread.setDaemon(true) 必須在 start() 前調用
  • 所有非守護線程結束 → JVM 退出 → 殺死所有守護線程
  • 守護線程創建的線程默認也是守護線程
for (int i = 0; i < 10; i++) {
    Thread d = new Thread(new SimpleDaemons());
    d.setDaemon(true);
    d.start();
}
Thread.sleep(175); // 主線程結束,守護線程隨之終止

線程加入

  • t1.join():當前線程等待 t1 終止
  • t1.join(millis):超時返回
  • 可被 interrupt() 中斷,拋出 InterruptedException
Sleeper sleepy = new Sleeper("Sleepy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy); // dopey.join(sleepy)
sleepy.join(); // main 等待 sleepy
// 輸出順序:Grumpy interrupted → Doc join completed → Sleepy awakened → Dopey join completed → main continue

異常處理機制

問題:main try-catch 無法捕獲子線程異常

ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(() -> { throw new RuntimeException(); });
// 異常丟失,只在控制台打印堆棧

方案 1:線程工廠設置 UncaughtExceptionHandler (JDK 5+)

class HandlerThreadFactory implements ThreadFactory {
    @Override public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setUncaughtExceptionHandler((thread, throwable) ->
            System.out.println("Thread " + thread + " crashed: " + throwable));
        return t;
    }
}
ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());

方案 2:全局默認處理器

Thread.setDefaultUncaughtExceptionHandler((t, e) ->
    System.out.println("Global handler: " + t + " -> " + e));
ExecutorService exec = Executors.newCachedThreadPool();

總結建議

  • 業務線程統一用 ExecutorService 管理,避免顯式 new Thread
  • 線程池大小根據任務類型調整:CPU 密集 ~ 核數,IO 密集 ~ 2*核數
  • 關鍵異常必須通過 UncaughtExceptionHandler 記錄,防止靜默失敗
  • 優雅關閉:shutdown() → awaitTermination() → shutdownNow()
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved