線程創建的三種標準方式
1. 繼承 Thread 類 (不推薦,繼承耦合)
class MyThread extends Thread {
@Override public void run() {
System.out.println("Thread: " + getName() + " running");
}
}
new MyThread().start(); // 必須調用 start(),而非 run()
2. 實現 Runnable 接口 (推薦,分離任務與執行)
class MyTask implements Runnable {
@Override public void run() {
System.out.println("Runnable: " + Thread.currentThread().getName());
}
}
new Thread(new MyTask()).start();
// 或線程池執行
executor.execute(new MyTask());
3. 實現 Callable + FutureTask (有返回值、可拋異常)
import java.util.concurrent.*;
class MyCallable implements Callable {
@Override public Integer call() throws Exception {
Thread.sleep(1000);
return 42; // 返回結果
}
}
// 用法
ExecutorService es = Executors.newSingleThreadExecutor();
Future future = es.submit(new MyCallable());
Integer result = future.get(); // 阻塞獲取結果
es.shutdown();
Thread 核心 API 速查表
| 方法 | 作用 | 注意 |
start() | 啟動線程,JVM 調用 run() | 只能調用一次,否則 IllegalThreadStateException |
run() | 線程執行體 | 直接調用不會啟動新線程,只是普通方法調用 |
sleep(ms) | 當前線程休眠 (靜態) | 不釋放鎖,拋 InterruptedException |
yield() | 當前線程讓出 CPU (靜態) | 僅重新參與調度,不保證切換 |
join() | 等待該線程終止 | 常用於主線程等待子線程 |
interrupt() | 設置中斷標誌位 | 不會強制停止,需代碼配合檢查 |
isInterrupted() | 檢查中斷標誌 (不清除) | 靜態 interrupted() 會清除標誌 |
setDaemon(true) | 設置守護線程 | 需在 start() 前調用;JVM 只有守護線程時退出 |
setName()/getName() | 設置/獲取線程名 | 調試、日誌追蹤關鍵 |
getId() | 獲取唯一線程 ID (long) | JVM 分配,不重複 |
getState() | 獲取線程狀態枚舉 | NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED |
setPriority(int) | 設置優先級 1-10 | 僅提示調度器,不可靠 |
currentThread() | 獲取當前執行線程 (靜態) | 最常用獲取上下文方式 |
線程生命周期狀態轉換
NEW --start()--> RUNNABLE (就緒/運行)
RUNNABLE --sleep/wait/join/IO--> TIMED_WAITING / WAITING / BLOCKED
TIMED_WAITING / WAITING / BLOCKED --超時/通知/獲取鎖--> RUNNABLE
RUNNABLE --run() 結束/拋出未捕獲異常--> TERMINATED
線程安全基礎:synchronized、volatile、ThreadLocal
synchronized (內置鎖)
// 同步方法 (鎖 this / Class 對象)
public synchronized void safeMethod() { }
// 同步代碼塊 (指定鎖對象)
public void safeBlock() {
synchronized (lockObject) { // lockObject 必須非 null、共享、不可變
// 臨界區
}
}
volatile (可見性、有序性、不保證原子性)
class VolatileDemo {
volatile boolean flag = false; // 寫入立即刷新主存,讀取立即從主存
volatile long counter = 0; // long/double 64位讀寫非原子,volatile 保證原子讀寫
void writer() { flag = true; counter++; }
void reader() { if (flag) System.out.println(counter); }
}
ThreadLocal (線程封閉,空間換時間)
class ThreadLocalDemo {
// 每個線程獨立副本,互不干擾
static final ThreadLocal formatter =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
static String format(Date date) {
return formatter.get().format(date); // 線程安全,無鎖
}
// 記得清理 (線程池場景必須)
static void clean() { formatter.remove(); }
}
線程池:ExecutorService 核心參數與最佳實踐
ThreadPoolExecutor 七大參數
new ThreadPoolExecutor(
corePoolSize, // 核心線程數 (常駐)
maximumPoolSize, // 最大線程數 (峰值)
keepAliveTime, // 非核心線程空閒存活時間
TimeUnit.SECONDS, // 時間單位
workQueue, // 任務隊列 (關鍵!)
threadFactory, // 線程工廠 (命名、守護、優先級)
handler // 拒絕策略 (隊列滿、線程數達最大時)
);
四大內置隊列選型指南
| 隊列 | 特點 | 適用場景 | 風險 |
ArrayBlockingQueue | 有界數組 | 固定緩衝、需控制內存 | 需預估容量 |
LinkedBlockingQueue | 無界鏈表 (默認 Integer.MAX_VALUE) | 一般業務、吞吐優先 | OOM 風險 (任務產生 > 消費) |
SynchronousQueue | 零容量、直接移交 | 高併發、快速任務、CachedThreadPool | 任務積壓直接拒絕/新建線程 |
DelayQueue | 延遲執行 (定時任務) | ScheduledThreadPoolExecutor | 特定場景 |
四大拒絕策略
AbortPolicy (默認):拋 RejectedExecutionException
CallerRunsPolicy:調用者線程執行任務 (降速回壓)
DiscardPolicy:靜默丟棄新任務
DiscardOldestPolicy:丟棄隊列最舊任務,嘗試重新提交
Executors 工廠方法陷阱 (阿里規約禁用)
| 方法 | 內部實現 | 風險 |
newFixedThreadPool | LinkedBlockingQueue 無界 | 任務堆積 OOM |
newSingleThreadExecutor | LinkedBlockingQueue 無界 | 任務堆積 OOM |
newCachedThreadPool | SynchronousQueue + 無限線程 | 線程爆炸 OOM |
newScheduledThreadPool | DelayedWorkQueue 無界 | 任務堆積 OOM |
生產環境推薦:自定義線程池
import java.util.concurrent.*;
public class ThreadPoolConfig {
public static ExecutorService createBusinessPool() {
return new ThreadPoolExecutor(
8, // core: CPU 密集型 = 核心數; IO 密集型 = 2*核心數
16, // max: 峰值緩衝
60, TimeUnit.SECONDS, // keepAlive
new ArrayBlockingQueue<>(2000), // 有界隊列,防 OOM
new ThreadFactoryBuilder()
.setNameFormat("biz-worker-%d") // 關鍵:有意義名稱
.setDaemon(false)
.build(),
new ThreadPoolExecutor.CallerRunsPolicy() // 回壓,保護系統
);
}
// 優雅關閉模板
public static void shutdown(ExecutorService pool, String name) {
pool.shutdown(); // 不再接受新任務
try {
if (!pool.awaitTermination(30, TimeUnit.SECONDS)) {
List remaining = pool.shutdownNow(); // 強制中斷
log.warn("{} 強制關閉,剩餘任務: {}", name, remaining.size());
}
} catch (InterruptedException e) {
pool.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
CompletableFuture:異步編排利器 (JDK 8+)
ExecutorService es = ThreadPoolConfig.createBusinessPool();
// 1. 供給型異步任務
CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
return "Hello";
}, es);
// 2. 消費型回調
cf1.thenAccept(s -> System.out.println("收到: " + s));
// 3. 轉換鏈
CompletableFuture cf2 = cf1.thenApply(String::length);
// 4. 組合多個 Future
CompletableFuture cf3 = CompletableFuture.supplyAsync(() -> "World", es);
CompletableFuture combined = cf1.thenCombine(cf3, (a, b) -> a + " " + b);
// 5. 異常處理
combined.exceptionally(ex -> {
log.error("異步鏈出錯", ex);
return "Default";
});
// 6. 等待所有完成
CompletableFuture.allOf(cf1, cf2, cf3).join();
es.shutdown();
總結
Java 線程編程核心在於:任務與執行分離 (Runnable/Callable)、線程池管理資源 (有界隊列、拒絕策略、命名)、同步工具選型 (synchronized/volatile/Lock/並發集合)、異步編排 (CompletableFuture)。牢記:禁止直接使用 Executors 默認工廠、線程池必須有界、守護線程慎用、中斷協作而非強制停止、ThreadLocal 線程池場景必須清理。掌握這些,即可構建高併發、穩定、可維護的多線程系統。