隨著CPU主頻觸頂(~4GHz)、多核成主流,多線程並行編程成為發揮硬件性能的唯一路徑。Java作為內置線程支持的主流語言,掌握其線程模型是高性能開發的必修課。本系列從最基礎概念切入,層層遞進構建完整知識體系。
| 概念 | 本質 | 創建方式 | 生命周期 | 屬於 |
|---|---|---|---|---|
| 線程對象 | Java堆上普通對象(Thread/Runnable實例) | new Thread()、new MyRunnable() | GC回收前存活 | Java語言層 |
| 線程 | OS內核調度實體,擁有PC寄存器、棧、上下文 | thread.start() → JNI調用pthread_create/CreateThread | run()結束/異常終止 | OS/硬件層 |
關鍵洞見:new Thread()僅創建Java對象,**不啟動OS線程**;start()才請求OS創建真實線程,並安排執行run()。對象可重用,線程一次性(start()只能調用一次)。
public class SingleThread {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println("Hello, World!");
}
}
}
啟動流程:
java創建)Thread.start()產生main()入口main()返回 → 主線程結束 → JVM進程退出(非守護線程全結束)此過程僅一條用戶線程(主線程),稱為單線程模型。JVM後台仍有GC、JIT、Finalizer等守護線程,但不可訪問。
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread say: Hello, World!");
}
}
public class MultiThread {
public static void main(String[] args) {
new MyThread(); // ① 僅創建線程對象,無線程啟動
new MyThread().start(); // ② 創建對象 + 啟動線程
System.out.println("Main say: Hello, World"); // ③ 主線程繼續執行
}
}
可能輸出順序(單核時間片輪轉):
Main say: Hello, World
Thread say: Hello, World!
或相反。調度非確定性是多線程核心特徵。
JavaThread統一抽象兩者,代碼無差別。JVM將Java線程1:1映射到OS內核線程(現代Linux/Windows/macOS),由OS調度器決定並發/並行。
class MyThread extends Thread {
@Override public void run() { ... }
}
Thread t = new MyThread();
t.start();
缺點:繼承佔用單繼承名額、線程對象與任務耦合、一個對象只能start()一次。
class MyTask implements Runnable {
@Override public void run() { ... }
}
Runnable task = new MyTask();
new Thread(task).start(); // 可創建多個Thread包裝同一Runnable
new Thread(task).start(); // 多線程共享同一任務實例
優勢:任務與線程分離、支持線程池、可共享狀態、函數式編程友好(Lambda() -> {})。
| 操作 | 方法 | 說明 |
|---|---|---|
| 啟動 | start() | 請求OS創建線程,異步返回,run()在新線程執行 |
| 等待終止 | join() / join(millis) | 當前線程阻塞,直到目標線程結束 |
| 睡眠 | Thread.sleep(millis) | 當前線程讓出CPU,不釋放鎖 |
| 讓步 | Thread.yield() | 暗示調度器重新調度,不保證 |
| 中斷 | interrupt() / isInterrupted() / interrupted() | 協作式中斷機制,不強制停止 |
| 守護線程 | setDaemon(true) | JVM僅剩守護線程時退出,需在start()前設置 |
| 優先級 | setPriority(1-10) | 提示調度器,平台相關性強,慎用 |
| 獲取當前 | Thread.currentThread() | 返回正在執行代碼的Thread對象 |
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Child: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) { break; }
}
});
t.start();
t.join(); // 主線程等待t結束
System.out.println("Main: child finished");
}
}
輸出:Child 0-4 全部打印後,才打印Main。join()實現線程順序協調。
本文確立三大基石:
start()啟動新線程,run()只是普通方法調用下一站:線程對象核心方法深度解析 — join()、sleep()、interrupt()、yield()、守護線程、線程組、ThreadLocal原理與內存洩漏。