多線程是 Java 並發編程的基石。本文涵蓋進程與線程概念、JVM 啟動機制、兩大實現方式、線程生命週期、調度與控制、線程安全問題與同步機制、線程安全集合,並附完整售票案例演示。
| 術語 | 定義 |
|---|---|
| 進程 | 執行中程式,資源分配獨立單位,擁有獨立記憶體空間 |
| 線程 | 進程內執行單元/路徑,CPU 調度基本單位,共享進程資源 |
| 並行 | 邏輯上同時發生,多 CPU 真正同一時刻執行 |
| 並發 | 物理上輪流佔用 CPU,單 CPU 透過時間片切換模擬同時 |
Java 採用搶佔式調度:優先級高者獲得 CPU 時間片機率大,同優先級隨機選擇。
java 命令啟動 JVM 進程,自動啟動主線程執行 main(),同時啟動GC 線程等,故 JVM 本身即多線程。class MyThread extends Thread {
@Override public void run() {
for (int i = 0; i < 200; i++) System.out.println(getName() + ":" + i);
}
}
public class Demo {
public static void main(String[] args) {
new MyThread().start(); // 必須呼叫 start(),不可直接呼叫 run()
}
}
start() vs run():start() 啟動新線程並由 JVM 呼叫 run();直接呼叫 run() 視同普通方法,單線程執行。
class MyTask implements Runnable {
@Override public void run() {
for (int i = 0; i < 100; i++) System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
public class Demo {
public static void main(String[] args) {
MyTask task = new MyTask();
new Thread(task, "Thread-A").start();
new Thread(task, "Thread-B").start(); // 同一任務物件,資料共享
}
}
優勢:避免單繼承限制;任務與線程分離,適合多線程賣同一資源場景。
| 方法 | 作用 | 關鍵點 |
|---|---|---|
| sleep(ms) | 線程休眠,釋放 CPU,不釋放鎖 | static,拋 InterruptedException |
| join() | 等待該線程終止 | 常用於主線程等待子線程 |
| yield() | 禮讓 CPU,重新參與搶佔 | static,不保證切換成功 |
| setDaemon(true) | 設為守護線程 | 必須在 start() 前呼叫;JVM 僅剩守護線程時退出 |
| interrupt() | 中斷線程(推薦) | 打斷阻塞狀態,拋 InterruptedException;stop() 已棄用 |

// 不安全版:重複賣票、負票數
class SellTicket implements Runnable {
private int tickets = 100;
public void run() {
while (true) {
if (tickets > 0) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + "賣第" + tickets-- + "張");
}
}
}
}
private Object lock = new Object();
public void run() {
while (true) {
synchronized (lock) { // 任意對象作鎖,多線程必須共用同一把鎖
if (tickets > 0) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + "賣第" + tickets-- + "張");
}
}
}
}
synchronized void sell():鎖為 this。static synchronized void sell():鎖為 ClassName.class(類字節碼物件)。| 傳統安全類 | 現代推薦做法 |
|---|---|
| Vector、Hashtable、StringBuffer | Collections.synchronizedList(new ArrayList<>())、ConcurrentHashMap、StringBuilder(單線程) |
原則:優先用無鎖/低鎖集合(java.util.concurrent 套件),必要時再手動同步。
// 優先級 1-10,預設 5
t1.setPriority(Thread.MAX_PRIORITY); // 10
t2.setPriority(Thread.MIN_PRIORITY); // 1
// 守護線程:背景服務(如 GC、日誌)
daemonThread.setDaemon(true); // 必須 start() 前
daemonThread.start();
Thread/Runnable 兩種啟動方式,理解 start() 與 run() 差異。sleep/join/yield/interrupt/daemon 控制線程行為。synchronized(代碼塊/方法/靜態方法)解決競態條件。java.util.concurrent 高階組件(ReentrantLock、CountDownLatch、ThreadPoolExecutor 等)。