Java 從 Green Thread 時代開始,演進到使用 OS Thread,然後到了 Java 21 版,正式採用 Virtual Thread,以適應微服務時代伺服器的變革。
Green Threads
JDK 為了跨平台的特性,要讓程式可以在單核心,沒有多個 thread 的 OS 上運作,所以設計了內建的 thread 跟 scheduler
在 JDK 1.1 (1997) 時期,Java 使用 green threads(由 JVM 在使用者空間模擬出來的執行緒,不直接用 OS thread)。
優點:跨平台,不依賴作業系統執行緒,能讓多執行緒程式在沒有多執行緒支援的 OS 上跑。
缺點:
JVM 本身要實作 thread scheduler,效能比不上 OS 提供的 thread。
遇到 blocking I/O(例如 read socket),整個 JVM scheduler 都會被卡住,所有 green threads 都會停住。
- 從 JDK 1.3 (2000) 開始,Java 全面切換到 1:1 OS threads 模型
Native Thread
作業系統核心會用 time-sharing 或 優先權排程 來管理 threads。
重量級資源單位
每個 OS thread 需要 stack (通常 1MB 預設)、TCB (thread control block)、kernel data structures。
建立/銷毀成本高 (微秒到毫秒級)。
數量有限
- 即使硬體支援很多核心,實務上 JVM 或應用程式能開的 OS thread 數量大約只有幾千到幾萬。
blocking I/O 會卡住 thread
假設某個 OS thread 正在
read()一個 socket,整個 thread 會被 kernel block。即使這時 CPU 沒事幹,這個 thread 對 JVM 來說就是「卡住不能用」。
搶佔式排程 (preemptive)
OS scheduler 會把 CPU 切給不同 threads。
context switch 成本高,要切換 CPU 狀態、register、stack。
共享記憶體
- 所有 thread 共用同一個 address space,必須透過鎖 (lock, monitor) 控制同步,容易出現 race condition、deadlock。
OS thread 模型對「大量 I/O 密集型應用」來說效率很差
適合少量、CPU 密集的任務
不適合製作非常大量的網路連線伺服器
Virtual Thread
- Project Loom 在 Java 19 引入預覽功能、Java 21 變成正式 GA 的一個重要新功能
輕量級:建立/銷毀成本非常低,幾 KB stack 就能跑。
blocking I/O 處理方式不同:
Virtual Thread 呼叫阻塞 API (
Socket.read()),JVM 會攔截並讓出 OS thread。這樣 OS thread 可以拿去執行其他 Virtual Thread,不會浪費資源。
數量級提升:
可以開數百萬個 virtual threads,對應數百萬個並發請求。
讓程式碼還是同步/直觀,但效能接近非同步 I/O 模型。
簡化程式碼:
- 不需要複雜的 callback、CompletableFuture、reactive pipeline,直接用同步程式碼就能寫出 scalable 程式。
把「blocking I/O」變得非阻塞化,同時又保留傳統同步 API 的簡單性,讓 Java 更適合現代微服務/高併發應用。
虛擬線程更適合 I/O 型或高併發場景。如果是非常 CPU密集或如果內部有同步鎖 (synchronized) 或重度共享資源競爭,則使用傳統線程。
Erlang Process
極度輕量:一個 process 只佔用幾 KB 記憶體,可以同時開數百萬個。由 BEAM VM 調度
獨立記憶體空間:每個 process 有自己的 heap/stack,不共享狀態。
排程由 BEAM 虛擬機控制:BEAM 用 OS threads(通常一個核心對應一個 scheduler thread)去執行上千萬個 Erlang processes。
preemptive scheduling:Erlang process 執行一定數量的 reductions(指令數)後會自動讓出 CPU。
Erlang process 的定位 比較接近 Java 的 Virtual Thread
因為 Erlang 從設計之初就為了 massive concurrency,整個 I/O 模型與錯誤隔離都是以「百萬 process」為目標;
Java Virtual Thread 是在既有 thread-based API 上加的輕量執行緒,強調「低成本封裝既有同步程式碼」。
Erlang Process vs Java Threads 比較
| 特性 | Erlang Process | Java OS Thread | Java Virtual Thread |
|---|---|---|---|
| 管理單位 | BEAM VM (使用 scheduler threads) | OS Kernel | JVM (基於 OS threads) |
| 重量級 / 輕量級 | 超輕量 (幾 KB) | 重量級 (MB) | 輕量 (KB 級) |
| 建立數量 | 百萬級 | 幾千~幾萬 | 百萬級 |
| 排程 | BEAM VM preemptive scheduling | OS scheduler | JVM scheduler |
| blocking I/O | 不會卡住整個 VM,process 掛起,scheduler 跑其他 process | 卡住 OS thread | 掛起虛擬執行緒,釋放 OS thread |
| 共享記憶體 | 不共享,透過 message passing | 共享,需要鎖 | 不共享(但可用同步物件) |
| 錯誤隔離 | 完整隔離,崩潰不會影響其他 process | 線程崩潰可能拖垮 JVM | 崩潰只影響該 virtual thread |
| 設計哲學 | 為 massive concurrency 與容錯而生 | 傳統 multi-threading | 保留同步 API,實現高併發 |
| 適用場景 | 聊天室、遊戲伺服器(每個玩家一個 process)、即時推播(pub/sub 模式) | I/O 密集、RPC、WebSocket | CPU 密集、JNI、非阻塞演算法 |
沒有留言:
張貼留言