2026/3/16

Java Virtual Thread

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、非阻塞演算法

沒有留言:

張貼留言