一、進程 vs 執行緒
- 進程:資源分配單位,擁有獨立記憶體空間(代碼、資料、堆、棧)。
- 執行緒:CPU 調度單位,隸屬於進程,共享進程記憶體(堆、方法區),各自擁有程式計數器、虛擬機棧、本地方法棧。
- Java 程式啟動即擁有主執行緒;
Thread 物件代表一條執行緒。
二、建立執行緒三種方式
| 方式 | 核心步驟 | 優缺點 |
| 繼承 Thread | 覆寫 run() → new MyThread().start() | 簡單,但單繼承限制,邏輯與執行緒控制耦合 |
| 實作 Runnable | 實作 run() → new Thread(new MyRunnable()).start() | 解耦任務與執行緒,可共享 Runnable 實例,推薦 |
| 實作 Callable + FutureTask | 實作 call() 可回傳值/拋例外 → FutureTask 包裝 → Thread 執行 | 支援回傳結果、異常傳播、可取消,配合執行緒池最佳 |
三、執行緒生命週期
NEW → RUNNABLE (start) → RUNNING (獲得 CPU)
↔ BLOCKED (鎖/IO)
↔ WAITING (wait/join/park)
↔ TIMED_WAITING (sleep/wait/join with timeout)
→ TERMINATED (run 結束/異常)
四、常用 API 速查
| 方法 | 說明 |
start() | 啟動執行緒,JVM 呼叫 run();不可直接呼叫 run() |
sleep(ms) | 靜態方法,當前執行緒休眠,**不釋放鎖** |
yield() | 靜態方法,暗示調度器讓出 CPU,不保證成功 |
join() | 當前執行緒等待目標執行緒終止 |
interrupt() | 設定中斷標記;阻塞方法會拋 InterruptedException |
isInterrupted() | 檢查中斷標記 (不清除) |
setDaemon(true) | 設為守護執行緒 (JVM 結束時不等待) |
setPriority(int) | 1~10,僅提示調度器,不可依賴 |
五、執行緒安全與同步
5.1 核心問題:可見性、原子性、有序性
5.2 synchronized 關鍵字
// 同步實例方法:鎖 this
public synchronized void add() { ... }
// 同步靜態方法:鎖 Class 物件
public static synchronized void staticAdd() { ... }
// 同步區塊:自定義鎖物件
private final Object lock = new Object();
public void add() {
synchronized (lock) { ... }
}
5.3 volatile 關鍵字
- 保證可見性:寫入後立即刷新到主記憶體,讀取時從主記憶體載入。
- 禁止指令重排序(JMM happens-before)。
- 不保證原子性:
volatile int i; i++; 仍非原子。
5.4 Lock 介面
ReentrantLock lock = new ReentrantLock();
lock.lock();
try { ... } finally { lock.unlock(); }
優於 synchronized:可中斷、可超時、公平鎖、多條件變數。
六、執行緒間通訊
6.1 wait/notify/notifyAll (Object 監視器)
- 必須在
synchronized 區塊內呼叫。
wait() 釋放鎖並進入 WAITING;notify() 喚醒單一執行緒。
- 經典模式:
while (condition) wait(); 防止虛假喚醒。
6.2 Condition (Lock 專用)
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();
// 生產者
lock.lock();
try { while (queue.size() == capacity) notFull.await(); queue.add(e); notEmpty.signal(); }
finally { lock.unlock(); }
6.3 高層並發工具 (JUC)
BlockingQueue:put/take 自動阻塞,生產消費首選。
CountDownLatch:倒數閂,等待 N 個任務完成。
CyclicBarrier:循環柵欄,N 執行緒互等。
Semaphore:信號量,控制並發存取數。
CompletableFuture:非阻塞組合式異步編程 (Java 8+)。
七、執行緒池
7.1 七大參數
new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit,
workQueue, threadFactory, handler)
corePoolSize:核心執行緒數(常駐)。
maximumPoolSize:最大執行緒數(隊列滿時擴容)。
workQueue:任務隊列(LinkedBlockingQueue 無界、ArrayBlockingQueue 有界、SynchronousQueue 直接移交)。
handler:拒絕策略(AbortPolicy 拋例外、CallerRunsPolicy 呼叫者執行、DiscardOldestPolicy 捨棄最舊)。
7.2 四大預設池
| 工廠方法 | 特徵 | 適用場景 |
newFixedThreadPool(n) | core=max=n,無界隊列 | 固定並發量,長期任務 |
newCachedThreadPool() | core=0,max=Integer.MAX,SynchronousQueue | 大量短任務,自動回收 |
newSingleThreadExecutor() | core=max=1,無界隊列 | 串行執行,保證順序 |
newScheduledThreadPool(n) | 支援定時/週期任務 | 排程、延遲執行 |
生產建議:避免預設池(OOM 風險),自訂參數、命名執行緒、監控隊列積壓。
八、總結
- 優先用
Runnable/Callable + 執行緒池,避免手動 new Thread。
- 共享可變狀態 →
synchronized/Lock/volatile/AtomicXxx/ThreadLocal。
- 生產消費 →
BlockingQueue;協調 → CountDownLatch/CyclicBarrier;異步組合 → CompletableFuture。
- 掌握 JMM (Java Memory Model) 原理,理解 happens-before,寫出正確高效並發程式。