Java基础 - Java Threads and Virtual Threads
Java线程
在 Java 19 之前,Java 线程模型都是 1:1 模型:1 Java Thread = 1 OS Thread。
Java 线程创建的过程 (new Thread(() -> work()).start();):
- 在 Java Heap 里 new 了个对象 (
Thread t = new Thread();) t.start();: 创建 OS 线程 (pthread_create())- 在操作系统眼中,该 Java 进程创建了一个线程,因此 OS 分配 native stack (大约1M~8M),Native Stack 用来运行 JVM 的 C++ 函数
- JVM 给线程分 Java Stack (mmap 一个内存区域作为 Java Stack,大小可以由
-Xss参数配置),Java Stack 用来运行 Java 方法 - 此时该 Java 线程与 OS 线程一一对应
线程的调度由操作系统来控制。
1:1模型的缺点
由于每创建一个 Java 线程都需要创建对应的 OS 线程,这限制了一个服务器创建大量的线程。尤其是当服务器的请求大多是 IO 密集型时,有限的线程大多都处于 Waiting 状态,大大占用了服务器的请求处理能力。在Linux中,内核为了处理系统调用、中断、上下文切换,必须为每个线程维护一个内核栈(通常是 16KB 或 8KB)。由于 OS 的 Kernal Space 有限,如果要创建10 万个线程,仅内核栈就需要 1.6GB 的物理内存。
在 Java 21 引入了虚拟线程的概念。
虚拟线程
虚拟线程 (Virtual Thread) 没有自己的 Kernel Stack。它是一个 Java 对象(java.lang.VirtualThread)。当一个虚拟线程需要 CPU 计算时,JVM 会把它“挂载 (Mount)” 到一个平台线程上。此时,虚拟线程借用了这个平台线程的 Kernel Stack 和 CPU 时间片来运行。 一旦虚拟线程由于 IO 而阻塞,JVM 会把它“卸载 (Unmount)”,归还平台线程。本质上,是 JVM 内实现的一套 user-level thread system。
- Unmount:将当前平台线程栈上的栈帧数据(包括程序计数器、局部变量)拷贝回 Java Heap 中。平台线程清空栈底,去执行下一个虚拟线程。
- 虚拟线程只有在 Native Stack(C++ 栈帧)为空时,才允许 Unmount。因此,JDK 21 对底层库做了大规模的重写,JDK 内部把 Socket 等 IO 操作全部改写成了 Non-blocking IO.
Java基础 - Java Threads and Virtual Threads
http://example.com/2025/07/06/JAVA_basis/java-virtual-threads/