ARTICLE · 1179132
Thread源码-jdk21
Thread类是 Java 线程的顶层抽象,代表一个线程实例,既可以是平台线程 (Platform Thread,传统 OS 线程包装),也可以是虚拟线程 (Virtual Thread,JDK21 正式 GA)。
JDK21 对 Thread 源码做了较大重构:新增虚拟线程支持,引入密封类`BaseVirtualThread`,新增`Thread.Builder`构建器 API,完善 continuation 协程底层能力。
类继承关系
java.lang.Object↳ java.lang.Thread implements Runnablesealed abstract class BaseVirtualThread extends Threadpermits VirtualThread, ThreadBuilders.BoundVirtualThread
- `VirtualThread`:final 类,虚拟线程核心实现
- `ThreadBuilders.BoundVirtualThread`:绑定型虚拟线程,内部嵌套类
二、核心成员变量
// 线程名称private volatile String name;// 线程优先级 1~10,默认5 当设置值超过该范围,则抛出异常private int priority;// 是否守护线程private boolean daemon;// 要执行的任务,Runnableprivate Runnable target;// 线程组private ThreadGroup group;// 线程IDprivate long tid;// 线程状态,volatileprivate volatile Thread.State state;// 线程组private ThreadGroup group;
State为内部枚举,共6大状态
public enum State {NEW, // 新建,还没调用start()RUNNABLE, // 可运行:OS就绪/运行中BLOCKED, // 阻塞:等待synchronized监视器锁WAITING, // 无限等待:wait()/join()无超时TIMED_WAITING, // 限时等待:sleep、wait(time)、join(time)TERMINATED // 线程执行完毕,终止}
注:`RUNNABLE` 包含操作系统层面「就绪」和「正在 CPU 运行」两种状态,JVM 不区分。
三、非核心成员变量
private volatile long eetop; // 线程存活标识//eetop:JVM 底层 C++ 对象 `JavaThread*` 的内存地址,用 long 保存原生指针,仅 JVM 内部使用,Java 代码不能读写核心作用:1. Java Thread 对象 ↔ JVM C++ JavaThread 的桥梁Java 堆里的`java.lang.Thread`只是 Java 层对象;真正管理栈、寄存器、操作系统线程的是 JVM 内部 C++ 的`JavaThread`。eetop存的就是这个 C++ 对象的内存地址。- `start()`成功后:JVM 把`JavaThread*`地址写入 eetop(非 0)- 线程执行结束退出时:JVM 把 eetop 置 02. isAlive()的判断依据thread.isAlive()底层直接判断:eetop != 0,不为 0 代表平台线程还存活。JDK 早期版本需要调用 native 方法进入 VM 读取,JDK21 优化成直接读这个 volatile 字段。3. JVM 各种 native 操作的入口句柄中断、join、获取栈帧、线程 dump、JNI 附加线程,JVM 拿到 Java Thread 对象后,读取 eetop,就能找到底层 C++ 线程实例,执行底层操作。4. volatile 含义保证多线程下可见性:JVM 在退出线程时写 0,其他线程读 eetop 能及时感知状态变更。private final FieldHolder holder; // 存放java线程的核心属性,//虚拟线程则是空的
FieldHolder是Thread类的静态内部类,源码如下:
private static class FieldHolder {final ThreadGroup group;final Runnable task;final long stackSize;volatile int priority;volatile boolean daemon;volatile int threadStatus;FieldHolder(ThreadGroup group,Runnable task,long stackSize,int priority,boolean daemon) {this.group = group;this.task = task;this.stackSize = stackSize;this.priority = priority;if (daemon)this.daemon = true;}}
四、构造方法
// 空构造,名字自动生成publicThread()// 传入Runnable任务public Thread(Runnable target)// 指定线程名public Thread(String name)// 任务+名称public Thread(Runnable target, String name)// 线程组 + 任务public Thread(ThreadGroup group, Runnable target)// 线程组+任务+名称+栈大小public Thread(ThreadGroup group, Runnable target, String name, long stackSize)
注:虚拟线程不使用上面的构造器,而是通过 `Thread.ofVirtual()` 构建器创建。
publicvoidstart() {synchronized (this) {// zero status corresponds to state "NEW".// 如果线程不是新建状态,则抛出异常if (holder.threadStatus != 0)throw new IllegalThreadStateException();//向操作系统申请创建系统线程并绑定java线程,//JVM 自动回调 run()start0();}}// native 本地方法,JVM申请创建操作系统线程private native voidstart0();
@Overridepublic void run() {Runnable task = holder.task;if (task != null) {Object bindings = scopedValueBindings();runWith(bindings, task);}}
@Hidden@ForceInlinefinal void runWith(Object bindings, Runnable op) {//确保 ScopedValue 绑定对象已经准备就绪,可以被栈遍历(stack walk)操作访问//当 JVM做栈回溯、异常打印、调试、线程 dump 的时候,需要读取当前线程的 ScopedValue 上下文;//这个调用保证`bindings`对象在栈上可见,不会被 JIT 优化掉,防止栈遍历的时候找不到上下文。ensureMaterializedForStackWalk(bindings);//执行用户业务 Runnable 任务。//此时 ScopedValue 上下文已经生效,业务代码可以读取继承过来的 ScopedValue。op.run();//维持对象可达性,阻止 JIT 编译器做指令重排、GC 提前回收`bindings`对象Reference.reachabilityFence(bindings);}
public static void sleep(long millis) throws InterruptedException {if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");}long nanos = MILLISECONDS.toNanos(millis);ThreadSleepEvent event = beforeSleep(nanos);try {if (currentThread() instanceof VirtualThread vthread) {//如果是虚拟线程, 开启虚拟线程的sleepvthread.sleepNanos(nanos);} else {//如果是普通线程,直接调用本地方法sleep0(nanos);}} finally {afterSleep(event);}}//本地方法,让当前线程进入 `TIMED_WAITING`,不释放锁//收到中断信号抛出 `InterruptedException`,并清除中断标记。private static native void sleep0(long nanos) throws InterruptedException;
//给线程打中断标记,不是立刻终止线程。//当线程被 `thread.interrupt()` 时,NIO 底层阻塞 IO 对象要执行的回调:中断这个阻塞在当前 IO 上的线程 t,//关闭通道、唤醒阻塞 native 调用,抛出`ClosedByInterruptException`public void interrupt() {if (this != Thread.currentThread()) {checkAccess();// thread may be blocked in an I/O operationsynchronized (interruptLock) { // 中断锁Interruptible b = nioBlocker;if (b != null) {interrupted = true; // 设置中断标识interrupt0(); // inform VM of interruptb.interrupt(this);return;}}}interrupted = true;interrupt0(); // inform VM of interrupt}// 查询当前线程中断标记,查询后清除中断标记public static boolean interrupted() {return currentThread().getAndClearInterrupt();}boolean getAndClearInterrupt() {boolean oldValue = interrupted;//我们有可能在读取该字段之后的一瞬间,线程就被中断了。//因此只有在我们读到中断标记为 true、并且准备返回 true 的场景下,才去清空这个标记**;//如果不这么做,就可能丢失一次中断事件。if (oldValue) {interrupted = false;clearInterruptEvent(); // 本地方法(由C++执行),清除中断事件}return oldValue;}// 判断线程是否被中断,查询中断标记,不清零public boolean isInterrupted() {return interrupted;}
// 判断当前线程是否存活public final boolean isAlive() {return alive();}boolean alive() {return eetop != 0; // 通过此标识判断os线程是否存活}
// 永久等待,直到目标线程终止public final void join() throws InterruptedException// 最多等待millis毫秒,超时就不再等,继续执行public final void join(long millis) throws InterruptedException// millis + nanos 纳秒级超时,几乎很少用public final void join(long millis, int nanos) throws InterruptedExceptionpublic final void join() throws InterruptedException {join(0);}public final void join(long millis) throws InterruptedException {if (millis < 0)throw new IllegalArgumentException("timeout value is negative");// 如果是虚拟线程且还存活,则将毫秒转换成纳秒,并等待执行if (this instanceof VirtualThread vthread) {if (isAlive()) {long nanos = MILLISECONDS.toNanos(millis);vthread.joinNanos(nanos);}return;}synchronized (this) {if (millis > 0) {if (isAlive()) {final long startTime = System.nanoTime();long delay = millis;do {wait(delay);} while (isAlive() && (delay = millis - NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);}} else {// millis=0:无限等待,只要目标线程存活,就一直waitwhile (isAlive()) {wait(0);}}}}
publicstaticvoidmain(String[] args) throws InterruptedException {System.out.println("====主线程开始执行====");Thread t = Thread.ofPlatform().start(() -> {try {Thread.sleep(1000);System.out.println("子线程执行完毕");} catch (InterruptedException e) {throw new RuntimeException(e);}});System.out.println("====主线程执行中=====");t.join();System.out.println("====主线程执行完=====");}
1. `join` 是 `synchronized` 方法:锁对象是目标 Thread 实例本身2. 循环判断 `isAlive()`:目标线程还活着,就执行 `this.wait()`,释放锁,当前线程进入 WAITING/TIMED_WAITING3. 当目标线程执行结束(TERMINATED),JVM 底层会自动调用 `this.notifyAll()`,唤醒所有在这个 Thread 对象上 wait 的线程4. 被唤醒后,循环再次检查`isAlive()`,如果线程已经终止,退出循环,join 返回注:不是 Java 代码里写 notify,是 JVM 底层在线程退出时,主动 notify 这个 Thread 对象上等待的线程!join核心要点:
1.join 底层是 wait,会释放锁,wait()会释放目标 Thread 对象的 monitor 锁;sleep 不会释放任何锁。2. 会抛出 InterruptedException,等待过程中,如果当前等待线程被 interrupt,直接抛异常,中断标记会被清除。3.虚假唤醒,为什么要用`while(isAlive())`而不是 if,因为 wait 存在虚假唤醒(不需要 notify 也可能被唤醒),唤醒后必须再次校验条件,防止提前退出。4.超时版本:等待指定时间,不管目标线程有没有结束,超时后直接返回
`join()` 是 `Thread` 的 final 方法,VirtualThread 没有重写 join,共用同一份 join 源码!- 虚拟线程调用join逻辑一样,等待目标线程结束- 但是注意:虚拟线程在 wait / 阻塞时会 unmount,载体线程可以复用,不会像平台线程那样卡住 OS 内核线程。
start0 () native 调用链路(JVM C++ 层)start0()在 `Thread.c` 注册本地方法:static JNINativeMethod methods[] = {{"start0", "()V", (void *)&JVM_StartThread},{"run", "()V", (void *)&JVM_Run},{"isAlive", "()Z", (void *)&JVM_IsThreadAlive},};1. Java `Thread.start()` → native `start0()` → `JVM_StartThread`(jvm.cpp)2. `JVM_StartThread` 创建 JVM 内部 `JavaThread`(C++ 对象)3. `JavaThread` 构造器:调用 `os::create_thread()`,向操作系统申请创建内核线程4. OS 创建内核线程成功后,JVM 调用 `os::start_thread()`,启动线程执行入口5. 线程入口函数:`thread_entry`,内部回调 Java 层的 `Thread.run()`
阶段 1:调用 start () 后,JVM 向操作系统创建内核线程1. JVM 调用操作系统 API- Linux:`pthread_create()`- Windows:`CreateThread()`2. OS 在内核里创建:TCB(Thread Control Block,线程控制块)TCB 保存:线程 ID、程序计数器 PC、寄存器上下文、栈指针、线程状态、优先级。3. OS 分配线程栈:- Java 线程栈:存放局部变量、方法调用栈帧- JVM 默认栈大小:Linux 一般 1MB,可以用 `-Xss` 修改4. 此时 OS 线程创建完成,状态标记为**就绪态 (READY)**,放入操作系统 CPU 调度队列。> 就绪态:线程准备好了,只差 CPU 时间片,不是正在运行阶段 2:操作系统 CPU 调度器调度线程OS 内核调度器(Linux CFS 完全公平调度器):- 多个就绪线程排队,按优先级 + 时间片分配 CPU 核心- 当这个线程抢到 CPU 时间片:1. 发生上下文切换:把 CPU 寄存器保存旧线程上下文,加载当前线程 TCB 里的寄存器、PC 程序计数器2. PC 指向 JVM 定义的线程入口函数 `thread_entry`(C++)阶段 3:JVM 入口函数,进入 Java run () 方法`thread_entry` 工作:1. 绑定当前 OS 内核线程 → JVM `JavaThread` 对象2. 切换到 Java 执行上下文3. 调用 Java `Thread.run()` 方法,执行我们写的业务代码4. 执行期间:- 遇到 IO 阻塞(socket、sleep、锁):OS 把线程置为**阻塞态**,让出 CPU,时间片直接交给其他线程- 时间片用完:OS 抢占,保存上下文,线程回到就绪队列阶段 4:run () 执行完毕,线程销毁1. `run()` 返回 → 回到 JVM `thread_entry`2. JVM 做收尾:关闭资源,通知线程组,标记 Java Thread 对象状态为 `TERMINATED`3. JVM 调用 OS 接口销毁内核线程,释放 TCB、线程栈内存4. Java 层 Thread 对象变成普通对象,等待 GC 回收> 内核线程销毁和 Java 对象 GC 是两件事!线程结束后 Java Thread 对象还在堆里,GC 晚一点回收。底层关键概念:用户态 / 内核态切换- Java 代码(run 里业务):用户态- 调用`sleep()`、`synchronized`、系统 IO:需要陷入内核态,由 OS 内核完成操作,有性能开销- 平台线程阻塞:内核线程直接阻塞,占用 OS 线程资源(虚拟线程这里行为不一样)
1. NEW — 新建定义:线程对象已创建,但尚未调用 start()。进入条件:Thread t = new Thread(task); // 此时 t.getState() == NEW离开条件:调用 t.start() → 进入 RUNNABLE。注意:NEW 状态的线程不占用任何 OS 资源,只是一个 Java 对象。2. RUNNABLE — 可运行定义:线程正在 JVM 中执行,或已准备好执行,等待 OS 调度。Java 层面:RUNNABLE 是一个复合状态,涵盖:OS 层面的 RUNNING(正在 CPU 上执行)OS 层面的 READY(就绪,等待 CPU 时间片)OS 层面的 I/O 等待(如 socket read,JVM 视为 RUNNABLE)为什么 I/O 等待也算 RUNNABLE:Java 规范明确定义 RUNNABLE 表示"在 Java 虚拟机中执行的线程",I/O 阻塞在 JVM 看来仍是"正在执行"的线程,不属于 Java 层面的阻塞。进入条件:start() 被调用后从 BLOCKED/WAITING/TIMED_WAITING 被唤醒从 I/O 阻塞返回离开条件:竞争锁失败 → BLOCKED调用 Object.wait() / Thread.join() / LockSupport.park() → WAITING调用 Thread.sleep() / Object.wait(timeout) / Thread.join(timeout) / LockSupport.parkNanos() / parkUntil() → TIMED_WAITINGrun() 执行完毕 → TERMINATED3. BLOCKED — 阻塞定义:线程等待获取监视器锁(monitor lock)而被阻塞。进入条件(唯一的触发场景):synchronized (obj) { // 如果 obj 的 monitor 被别的线程持有,则 BLOCKED...}或synchronized void method() { ... } // 方法级的 synchronized离开条件:成功获取 monitor → RUNNABLE。关键点:BLOCKED 只与 synchronized 相关,不涉及 Lock(ReentrantLock 等)。使用 ReentrantLock 竞争失败时,线程处于 WAITING 或 TIMED_WAITING(取决于 lock() 还是 tryLock(timeout)),不是 BLOCKED。4. WAITING — 无限期等待定义:线程无限期等待另一个线程执行特定操作。进入条件(三种方法):方法 唤醒方式Object.wait() Object.notify() / notifyAll()Thread.join() 目标线程终止LockSupport.park() LockSupport.unpark(thread)离开条件:收到对应的通知/唤醒被 interrupt() 中断(抛 InterruptedException,仅限 wait/join)不消耗 CPU,线程被挂起在 OS 层面注意:wait() 和 join() 在进入 WAITING 前会释放锁(wait 释放 monitor,join 内部通过 wait 实现),但 LockSupport.park() 不释放任何锁。5. TIMED_WAITING — 限时等待定义:线程在指定时间内等待另一个线程执行操作。进入条件(五种方法):Thread.sleep(millis) 毫秒Object.wait(timeout) 毫秒Thread.join(millis) 毫秒LockSupport.parkNanos(nanos) 纳秒LockSupport.parkUntil(deadline) 绝对时间戳离开条件:超时到期收到对应通知/唤醒(同 WAITING)被中断(sleep/wait/join 抛 InterruptedException)与 WAITING 的唯一区别:带超时参数,时间到了自动返回。6. TERMINATED — 已终止定义:线程的 run() 方法执行完毕(正常返回或抛出未捕获异常)。进入条件:run() 正常返回run() 抛出异常且未被捕获(线程终止,异常由 UncaughtExceptionHandler 处理)离开条件:无。TERMINATED 是终态。注意:已终止的线程不能再次 start(),否则抛 IllegalThreadStateException。
start()NEW ──────────────────────────────→ RUNNABLE││┌─────────────────────────────┼─────────────────────────────┐│ │ ││ 竞争 monitor 失败 │ sleep(timeout) │ run() 结束↓ │ wait(timeout) ↓BLOCKED │ join(timeout) TERMINATED│ │ parkNanos/parkUntil│ 获取 monitor ↓└────────────────────→ TIMED_WAITING││ 超时/唤醒/中断↓RUNNABLE│┌─────────────────────────────┤│ ││ wait() │ park()│ join() │↓ │WAITING ──────────────────────────┘││ notify()/notifyAll()│ unpark()│ 中断↓RUNNABLE
synchronized | 竞争失败 | 获取 monitor | — | 不可中断 |
Object.wait() | WAITING | notify/notifyAll | 释放 monitor | 可中断 |
Object.wait(timeout) | TIMED_WAITING | 超时/通知 | 释放 monitor | 可中断 |
Thread.join() | WAITING | 目标线程终止 | — | 可中断 |
Thread.join(timeout) | TIMED_WAITING | 超时/终止 | — | 可中断 |
Thread.sleep(millis) | TIMED_WAITING | 超时 | 不释放 | 可中断 |
LockSupport.park() | WAITING | unpark | 不释放 | 不可中断 |
LockSupport.parkNanos() | TIMED_WAITING | 超时/unpark | 不释放 | 不可中断 |
LockSupport.parkUntil() | TIMED_WAITING | 超时/unpark | 不释放 | 不可中断 |
JAVA 状态 | OS 线程状态 | 是否占用 CPU |
NEW | 无OS线程 | 否 |
RUNNABLE(就绪) | READY | 否 |
RUNNABLE(运行中) | RUNNING | 是 |
RUNNABLE(I/O 等待) | BLOCKED (内核态) | 否 |
BLOCKED | BLOCKED (等待锁) | 否 |
WAITING | SLEEPING/BLOCKED | 否 |
TIMED_WAITING | SLEEPING/BLOCKED | 否 |
TERMINATED | 已回收 | 否 |
注:Java 的 RUNNABLE 不对应 OS 的单一状态,这就是为什么 RUNNABLE 的线程可能既没在跑也没在等 Java 锁,而是阻塞在 I/O。
1.虚拟线程介绍
虚拟线程,M:N 映射,用户态轻量线程,不直接绑定 OS 内核线程。
final class VirtualThread extends BaseVirtualThread {private static final Unsafe U = Unsafe.getUnsafe(); //作用:底层操作入口,用于 park/unpark 载体线程、获取字段偏移量、CAS 状态转换private static final ContinuationScope VTHREAD_SCOPE = new ContinuationScope("VirtualThreads");//作用:所有虚拟线程共享的延续体作用域,Continuation.yield 时冻结栈帧的边界标识private static final ForkJoinPool DEFAULT_SCHEDULER = createDefaultScheduler();//作用:默认调度器,FIFO 模式 ForkJoinPool,将 runContinuation 分派到载体线程执行private static final ScheduledExecutorService UNPARKER = createDelayedTaskScheduler();//作用:独立的超时唤醒调度器,用平台线程处理 parkNanos/sleepNanos 的定时 unpark,防止调度器被 pinning 阻塞导致死锁private static final int TRACE_PINNING_MODE = tracePinningMode();//作用:pinning 追踪模式,由 jdk.tracePinnedThreads 属性决定,0=不追踪 1=打印堆栈 2=仅概要private static final long STATE = U.objectFieldOffset(VirtualThread.class, "state");//作用:state 字段的内存偏移量,用于 Unsafe CAS 原子状态转换private static final long PARK_PERMIT = U.objectFieldOffset(VirtualThread.class, "parkPermit");//作用:parkPermit 字段的内存偏移量,用于 CAS 原子设置 park 许可private static final long CARRIER_THREAD = U.objectFieldOffset(VirtualThread.class, "carrierThread");//作用:carrierThread 字段的内存偏移量,用于原子读写载体线程引用private static final long TERMINATION = U.objectFieldOffset(VirtualThread.class, "termination");//作用:termination 字段的内存偏移量,用于 join() 协调对象的原子操作// scheduler and continuationprivate final Executor scheduler;//作用:该虚拟线程的调度器,默认 DEFAULT_SCHEDULER,可自定义,submitRunContinuation 提交任务的目标private final Continuation cont;//作用:核心延续体对象,负责栈帧冻结/恢复,run() 委托给 cont.run(),yield 通过 cont 触发private final Runnable runContinuation;//作用:提交给调度器的实际任务,载体线程取出后执行它,内部调用 task.run()// virtual thread state, accessed by VMprivate volatile int state;//作用:虚拟线程内部状态,由 VM 直接读写,通过 Unsafe CAS 原子转换(NEW/STARTED/RUNNING/PARKED/PINNED/TERMINATED 等)private static final int NEW = 0;//作用:新建状态,start() 之前private static final int STARTED = 1;//作用:已启动,start() 已调用但尚未首次挂载private static final int RUNNABLE = 2; // runnable-unmounted//作用:就绪但未挂载,已提交到调度器队列等待载体线程取出private static final int RUNNING = 3; // runnable-mounted//作用:运行中且已挂载,正在载体线程上执行private static final int PARKING = 4;//作用:正在尝试挂起,已调用 yield 但尚未确认是否成功private static final int PARKED = 5; // unmounted//作用:已挂起且已卸载,栈帧冻结在堆上,载体线程已释放private static final int PINNED = 6; // mounted//作用:被钉住,无法卸载,载体线程被直接阻塞private static final int YIELDING = 7; // Thread.yield//作用:正在执行 Thread.yield(),主动让出载体线程private static final int TERMINATED = 99;//作用:已终止,任务执行完毕或启动失败private static final int SUSPENDED = 1 << 8;//作用:挂起状态位,与基础状态按位或组合,用于 JVMTI 调试挂起private static final int RUNNABLE_SUSPENDED = (RUNNABLE | SUSPENDED);//作用:就绪且被 JVMTI 挂起,等待恢复private static final int PARKED_SUSPENDED = (PARKED | SUSPENDED);//作用:已挂起且被 JVMTI 挂起,双重挂起状态private volatile boolean parkPermit;//作用:park 许可,unpark 时 CAS 置 true,park 前检查,为 true 则立即返回不阻塞private volatile Thread carrierThread;//作用:当前挂载的载体线程引用,mount 时设置,unmount 时清空,PARKED 时为 nullprivate volatile Object termination;//作用:终止协调对象,join() 时延迟创建,用于等待线程与终止线程之间的同步private final Object interruptLock = new Object();//作用:中断状态同步锁,mount/unmount 与 interrupt() 之间同步中断标志,防止竞态private volatile boolean interrupted;//作用:虚拟线程自身的中断状态,与载体线程中断状态在 mount/unmount 时双向同步private volatile long timeout;//作用:超时时长(纳秒),afterYield 中用于区分 PARKING 与 TIMED_PARKINGprivate volatile Future<?> timeoutTask;//作用:超时定时任务句柄,parkNanos 时向 UNPARKER 提交,提前唤醒时可 cancelprivate static class VThreadContinuation extends Continuation {//作用:Continuation 子类,封装虚拟线程与用户任务,将执行体绑定为 () -> vthread.run(task)private final VirtualThread vthread;//作用:所属虚拟线程引用private final Runnable task;//作用:用户任务,在 runContinuation 中被调用}VirtualThread(Executor scheduler, String name, int characteristics, Runnable task) {//作用:构造方法,scheduler 为 null 时用 DEFAULT_SCHEDULER,name 为 null 时自动生成,创建 Continuation 并绑定 this::runContinuationsuper(name, characteristics, false);//作用:调用父类构造,虚拟线程始终为 daemonthis.scheduler = (scheduler != null) ? scheduler : DEFAULT_SCHEDULER;//作用:设置调度器this.cont = new VThreadContinuation(this, task);//作用:创建延续体this.runContinuation = this::runContinuation;//作用:绑定任务提交体}static VirtualThread createVirtualThread(Executor scheduler, String name, int characteristics, Runnable task) {//作用:静态工厂,供 ThreadBuilders 调用,处理 null 参数与默认名称生成@Overridevoid start(ThreadContainer container) {//作用:启动入口if (!compareAndSetState(NEW, STARTED)) {//作用:CAS NEW→STARTED,保证 start() 只调用一次throw new IllegalThreadStateException("Already started");//作用:重复启动抛异常}setThreadContainer(container);//作用:注册到容器boolean addedToContainer = false;//作用:容器注册标记boolean started = false;//作用:启动成功标记try {container.onStart(this);//作用:通知容器线程启动addedToContainer = true;//作用:标记已注册inheritScopedValueBindings(container);//作用:继承 ScopedValue 绑定submitRunContinuation();//作用:提交到调度器started = true;//作用:标记启动成功} finally {if (!started) {//作用:启动失败setState(TERMINATED);//作用:设置终止状态afterTerminate(addedToContainer, false);//作用:终止后清理}}}@Overridepublic void run() {//作用:委托给 Continuation.run(),直接调用不执行用户任务cont.run();//作用:触发延续体运行}private void runContinuation() {//作用:Continuation 的执行体,在载体线程上执行try {task.run();//作用:执行用户任务} finally {afterTask();//作用:任务完成后清理}}private void afterTask() {//作用:任务完成或异常后的清理,发出 VirtualThreadEndEvent JFR 事件、从容器移除、setState(TERMINATED)、清理引用@ChangesCurrentThread@ReservedStackAccessprivate void mount() {//作用:将虚拟线程挂载到载体线程startTransition(true);//作用:开始状态转换Thread carrier = Thread.currentCarrierThread();//作用:获取当前载体线程CARRIER_THREAD.setRelease(this, carrier);//作用:记录载体线程引用carrier.setCurrentThread(this);//作用:核心操作,Thread.currentThread() 切换为虚拟线程if (interrupted) {//作用:虚拟线程已中断carrier.setInterrupt();//作用:传播中断到载体线程} else if (carrier.isInterrupted()) {//作用:载体线程有中断synchronized (interruptLock) {//作用:同步锁if (!interrupted) carrier.clearInterrupt();//作用:清除载体线程中断}}}@ChangesCurrentThread@ReservedStackAccessprivate void unmount() {//作用:将虚拟线程从载体线程卸载Thread carrier = Thread.currentCarrierThread();//作用:获取当前载体线程carrier.setCurrentThread(carrier);//作用:先恢复 Thread.currentThread()synchronized (interruptLock) {//作用:同步锁CARRIER_THREAD.setRelease(this, null);//作用:清空载体线程引用}carrier.clearInterrupt();//作用:清除载体线程中断endTransition(false);//作用:结束状态转换}@ChangesCurrentThreadprivate void switchToCarrierThread() {//作用:临时切换到载体线程上下文,用于提交任务、执行特殊逻辑@ChangesCurrentThreadprivate void switchToVirtualThread(VirtualThread vthread) {//作用:恢复回虚拟线程上下文@ChangesCurrentThread<V> V executeOnCarrierThread(Callable<V> task) throws Exception {//作用:在载体线程上执行任务,不挂载虚拟线程void park() {//作用:虚拟线程挂起(对应 LockSupport.park)assert Thread.currentThread() == this;setState(PARKING);//作用:设置正在尝试挂起boolean yielded = yieldContinuation();//作用:尝试冻结栈帧if (!yielded) {//作用:yield 失败doPark();//作用:退化为载体线程阻塞}}void parkNanos(long nanos) {//作用:带超时的挂起long startTime = System.nanoTime();setState(TIMED_PARKING);//作用:设置定时挂起boolean yielded = yieldContinuation();//作用:尝试冻结栈帧if (!yielded) {//作用:pinninglong deadline = startTime + nanos;if (deadline < 0L) deadline = Long.MAX_VALUE;//作用:溢出保护parkOnCarrierThread(true, deadline - System.nanoTime());//作用:载体线程定时 park}}private void doPark() {//作用:pinning 场景下的无限期 park,委托给 parkOnCarrierThreadprivate void parkOnCarrierThread(boolean timed, long nanos) {//作用:pinning 退化路径,直接在载体线程上阻塞var pinnedEvent = new VirtualThreadPinnedEvent();//作用:JFR pinning 事件pinnedEvent.begin();//作用:开始事件setState(PINNED);//作用:设置被钉住状态try {if (!parkPermit) {//作用:无 park 许可if (!timed) U.park(false, 0);//作用:无限期阻塞载体线程else if (nanos > 0) U.park(false, nanos);//作用:定时阻塞载体线程}} finally {setState(RUNNING);//作用:恢复运行状态}setParkPermit(false);//作用:消耗 park 许可pinnedEvent.commit();//作用:提交 JFR 事件}@ChangesCurrentThreadvoid unpark() {//作用:唤醒虚拟线程Thread currentThread = Thread.currentThread();//作用:获取当前线程if (!getAndSetParkPermit(true) && currentThread != this) {//作用:原子设置许可int s = state();//作用:读取状态if (s == PARKED && compareAndSetState(PARKED, RUNNABLE)) {//作用:CAS PARKED→RUNNABLEif (currentThread instanceof VirtualThread vthread) {//作用:被另一虚拟线程调用Thread carrier = vthread.carrierThread;carrier.setCurrentThread(carrier);//作用:临时切换到载体线程try { submitRunContinuation(); }//作用:提交任务finally { carrier.setCurrentThread(vthread); }//作用:恢复虚拟线程} else {submitRunContinuation();//作用:平台线程直接提交}} else if (s == PINNED) {//作用:pinning 场景synchronized (carrierThreadAccessLock()) {//作用:同步锁Thread carrier = carrierThread;if (carrier != null && state() == PINNED) {U.unpark(carrier);//作用:直接唤醒载体线程}}}}}private boolean getAndSetParkPermit(boolean newValue) {//作用:原子设置 park 许可,返回旧值private void setParkPermit(boolean newValue) {//作用:直接设置 park 许可(非 CAS)@Hiddenprivate boolean yieldContinuation() {//作用:触发 Continuation.yield(VTHREAD_SCOPE)return Continuation.yield(VTHREAD_SCOPE);//作用:返回 true 冻结成功;返回 false pinning}void tryYield() {//作用:Thread.yield() 实现assert Thread.currentThread() == this;setState(YIELDING);//作用:设置正在让出try {yieldContinuation();//作用:尝试让出载体线程} finally {if (state() != RUNNING) {//作用:yield 失败setState(RUNNING);//作用:恢复运行状态}}}private void afterYield() {//作用:yield 后由载体线程执行的状态处理assert carrierThread == null;//作用:此时已卸载if (currentThread() instanceof CarrierThread ct) {ct.endBlocking();//作用:通知载体线程阻塞结束}int s = state();//作用:读取状态if (s == PARKING || s == TIMED_PARKING) {//作用:park 场景int newState = (s == PARKING) ? PARKED : TIMED_PARKED;setState(newState);//作用:转为已挂起if (parkPermit && compareAndSetState(newState, UNPARKED)) {//作用:yield 期间已有 unparklazySubmitRunContinuation();//作用:懒提交}} else if (s == YIELDING) {//作用:Thread.yield 场景setState(YIELDED);//作用:转为已让出if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) {externalSubmitRunContinuation(ct.getPool());//作用:放入本地队列} else {submitRunContinuation();//作用:提交到全局队列}}}void sleepNanos(long nanos) throws InterruptedException {//作用:虚拟线程 sleepif (nanos <= 0) return;if (Thread.interrupted()) throw new InterruptedException();//作用:先检查中断setState(TIMED_PARKING);//作用:设置定时挂起boolean yielded = yieldContinuation();//作用:尝试冻结栈帧if (!yielded) {//作用:pinninglong deadline = System.nanoTime() + nanos;parkOnCarrierThread(true, deadline - System.nanoTime());//作用:载体线程定时 park}if (Thread.interrupted()) throw new InterruptedException();//作用:唤醒后再次检查中断}private void submitRunContinuation() {//作用:将 runContinuation 提交给调度器try {scheduler.execute(runContinuation);//作用:提交任务} catch (RejectedExecutionException ree) {submitFailed(ree);//作用:提交失败处理}}private void lazySubmitRunContinuation(ForkJoinPool pool) {//作用:懒提交优化pool.lazySubmit(ForkJoinTask.adapt(runContinuation));//作用:直接放入本地队列}private void externalSubmitRunContinuation(ForkJoinPool pool) {//作用:外部提交,放入载体线程本地队列private void submitFailed(RejectedExecutionException ree) {//作用:提交失败处理,发出 VirtualThreadSubmitFailedEvent JFR 事件@ChangesCurrentThreadprivate Future<?> scheduleUnpark(long nanos) {//作用:向 UNPARKER 提交超时唤醒任务Thread carrier = this.carrierThread;carrier.setCurrentThread(carrier);//作用:切换到载体线程try {return UNPARKER.schedule(() -> unpark(), nanos, NANOSECONDS);//作用:提交延迟唤醒} finally {carrier.setCurrentThread(this);//作用:恢复虚拟线程}}@ChangesCurrentThreadprivate void cancel(Future<?> future) {//作用:取消超时任务private boolean compareAndSetState(int expected, int newValue) {//作用:CAS 状态转换return U.compareAndSetInt(this, STATE, expected, newValue);//作用:Unsafe CAS}private void setState(int newValue) {//作用:直接设置状态(volatile 写)int state() {//作用:读取当前状态@Overridepublic void interrupt() {//作用:中断虚拟线程if (state() == TERMINATED) return;//作用:已终止直接返回synchronized (interruptLock) {interrupted = true;//作用:设置中断标志}if (state() == PARKED) {//作用:已挂起unpark();//作用:唤醒虚拟线程}}boolean isInterrupted() {//作用:返回中断状态static boolean interrupted() {//作用:返回并清除当前虚拟线程中断状态@Overridepublic void join() throws InterruptedException {//作用:等待虚拟线程终止@Overridepublic void join(long millis) throws InterruptedException {//作用:带超时的 joinprivate void afterDone(boolean notifyContainer) {//作用:任务完成后的最终清理setState(TERMINATED);//作用:设置终止状态CountDownLatch termination = this.termination;if (termination != null) termination.countDown();//作用:唤醒 join 等待者if (notifyContainer) threadContainer().onExit(this);//作用:通知容器clearReferences();//作用:清除引用}private void afterTerminate(boolean notifyContainer, boolean executed) {//作用:终止后的统一收尾private void clearReferences() {//作用:清除 ThreadLocal、nioBlocker、ScopedValue 绑定等引用,帮助 GCprivate ThreadContainer threadContainer() {//作用:返回虚拟线程所属的容器private void setThreadContainer(ThreadContainer container) {//作用:设置所属容器private void inheritScopedValueBindings(ThreadContainer container) {//作用:继承 ScopedValue 绑定private Thread carrierThread() {//作用:返回当前载体线程引用private void setCarrierThread(Thread carrier) {//作用:设置载体线程引用(volatile 写)private Object carrierThreadAccessLock() {//作用:返回用于保护 carrierThread 字段的锁对象@Overridepublic Thread.State getState() {//作用:将内部状态映射为 Thread.State// NEW→NEW;STARTED/RUNNING/PARKING/TIMED_PARKING/YIELDING→RUNNABLE// PARKED/PINNED→WAITING;TIMED_PARKED/TIMED_PINNED→TIMED_WAITING// TERMINATED→TERMINATED}@Overridepublic boolean isAlive() {//作用:是否处于活动状态(非 NEW 且非 TERMINATED)private void notifyJvmtiMount(boolean hide) {//作用:通知 JVMTI 代理即将挂载/卸载private void notifyJvmtiUnmount(boolean hide) {//作用:通知 JVMTI 代理即将卸载private static void toggleJvmtiTmpVTMSTrans(boolean enable) {//作用:切换 JVMTI 临时线程挂起状态static ForkJoinPool createDefaultScheduler() {//作用:创建默认调度器,并行度=CPU 核心数,asyncMode=true(FIFO),使用 CarrierThread 作为工作线程static ScheduledExecutorService createDelayedTaskScheduler() {//作用:创建 UNPARKER,使用 InnocuousThread 作为平台线程static int tracePinningMode() {//作用:读取 jdk.tracePinnedThreads 系统属性,返回 TRACE_PINNING_MODE}
Continuation | 冻结当前虚拟线程的 Java 栈帧到堆上的 StackChunk,或从 StackChunk 恢复回栈 |
CarrierThread | 真正干活的平台线程,从 ForkJoinPool 取出虚拟线程任务执行 |
ForkJoinPool | 默认调度器,维护 CarrierThread 线程池,负责把 runContinuation 分派给空闲载体线程 |
UNPARKER | 独立平台线程池,处理 parkNanos/sleepNanos 的定时唤醒 |
VTHREAD_SCOPE | ContinuationScope,标识"这是虚拟线程的延续体",供 yield 判断冻结边界 |
Thread.startVirtualThread(task)→ new VirtualThread(scheduler, name, characteristics, task)→ new VThreadContinuation(this, task) // 绑定执行体→ thread.start()→ start(container)→ CAS(NEW, STARTED) // 状态推进→ container.onStart(this) // 注册到容器→ inheritScopedValueBindings(...) // 继承 ScopedValue→ submitRunContinuation()→ DEFAULT_SCHEDULER.execute(runContinuation) // 提交到 ForkJoinPool
CarrierThread 从 ForkJoinPool 取出 runContinuation→ Continuation.run() // VM 原语,进入虚拟线程栈→ mount()→ CARRIER_THREAD.setRelease(this, carrier) // 记录载体线程→ carrier.setCurrentThread(this) // Thread.currentThread() 变为虚拟线程→ runContinuation()→ task.run() // 用户代码开始执行
核心操作:carrier.setCurrentThread(this)。载体线程内部有个"当前线程"指针,平时指向自己,挂载虚拟线程时临时指向虚拟线程对象。这样虚拟线程里的 Thread.currentThread() 返回的是虚拟线程,而不是载体线程。
task 内部调用 LockSupport.park()→ VirtualThread.park()→ setState(PARKING) // 标记:正在尝试挂起→ yieldContinuation()→ Continuation.yield(VTHREAD_SCOPE) // VM 原语,尝试冻结栈帧→ [VM] freeze 栈帧 → StackChunk 对象(堆上)→ unmount() // 卸载:恢复 Thread.currentThread()→ 控制权返回载体线程→ afterYield() [由载体线程执行]→ setState(PARKED) // 状态推进:已挂起→ 检查 parkPermit // 若期间有 unpark 到达,立即重提交
另一个线程调用 LockSupport.unpark(vt)→ VirtualThread.unpark()→ getAndSetParkPermit(true) // 原子设置许可→ CAS(PARKED, RUNNABLE) // 状态推进→ submitRunContinuation()→ DEFAULT_SCHEDULER.execute(runContinuation) // 重新提交到 ForkJoinPool某个 CarrierThread 取出 runContinuation→ Continuation.run()→ [VM] thaw StackChunk → 恢复栈帧到载体线程栈→ mount()→ carrier.setCurrentThread(this)→ 从 yield 返回点继续执行→ task.run() 从 park() 之后继续
注:虚拟线程被唤醒后不一定是原来那个载体线程执行它,任意空闲的载体线程都可以。这就是 M:N 调度的本质——M 个虚拟线程映射到 N 个载体线程。
4.5.任务结束
task.run() 执行完毕→ afterTask()→ VirtualThreadEndEvent.commit() // JFR 事件→ container.onExit(this)→ afterDone()→ setState(TERMINATED)→ termination.countDown() // 唤醒 join() 等待者→ clearReferences() // 清除 ThreadLocal、nioBlocker 等引用
5.状态转换图
NEW ──start()──→ STARTED ──首次挂载──→ RUNNING│ ││ ├──park()──→ PARKING ──yield成功──→ PARKED│ │ ││ │ └──unpark()──→ RUNNABLE│ ││ ├──park()──→ PARKING ──yield失败──→ PINNED│ │ ││ │ └──unpark(carrier)──→ RUNNING│ ││ ├──Thread.yield()──→ YIELDING ──→ YIELDED│ ││ └──任务完成──→ TERMINATED│└──启动失败──→ TERMINATED
6.Pinning(钉住)问题
yieldContinuation() 返回 false→ parkOnCarrierThread()→ VirtualThreadPinnedEvent.begin() // JFR 事件→ setState(PINNED)→ U.park(false, nanos) // 直接阻塞载体线程→ 唤醒后 setState(RUNNING)
解决办法:JDK 24 的 JEP 491 通过重写 ObjectMonitor 的挂起逻辑,让 monitor 竞争也能被 Continuation 冻结,从而消除 synchronized 导致的 pinning。
7.park/unpark 语义
与 LockSupport 一致的语义:
park():若无许可,挂起;若有许可,消耗许可立即返回
unpark():设置许可;若线程正在挂起,唤醒它
关键差异:
平台线程 park() 挂起的是 OS 线程
虚拟线程 park() 挂起的是虚拟线程本身,载体线程被释放
虚拟线程 pinning 时 park() 退化为 U.park(),直接挂起载体线程
8.调度优化
lazySubmit:当载体线程本地队列为空时,把任务直接放进本地队列,避免全局队列的锁竞争和线程唤醒开销。
externalSubmit:Thread.yield 场景下,优先把任务放进当前载体线程本地队列。
UNPARKER 独立:超时唤醒任务由独立的平台线程池处理,避免调度器被pinning 阻塞时超时任务无法执行导致死锁。
9.虚拟线程总结
虚拟线程本质是 "用户态线程 + Continuation + 载体线程复用":
Continuation 提供栈帧的挂起/恢复能力
CarrierThread 提供真正执行 Java 代码的载体
ForkJoinPool 提供 M:N 调度
mount/unmount 通过修改载体线程的 currentThread 指针,让虚拟线程对 Java 代码透明
park/unpark 在挂载状态下挂起虚拟线程、释放载体线程
九、平台线程 vs 虚拟线程的状态差异
维度 | 平台线程 | 虚拟线程 |
状态数量 | 6种(Thread.State) | 内部11种,映射后也是6种 |
状态存储 | OS线程状态直接反映 | 由VirtualThread.state 字段维护 |
RUNNABLE含义 | 包括就绪、运行、I/O 阻塞 | 包括就绪、运行,不包括挂起 |
BLOCKED | synchronized 竞争失败 | 不出现 BLOCKED(pinning 时映射为 RUNNABLE) |
WAITING | park/wait/join 挂起 | 内部 PARKED,映射为 WAITING |
TERMINATED | OS 线程销毁 | Continuation 结束,引用清理 |
状态查询 | Thread.getState()读OS | Thread.getState()读state字段+映射 |