夜雨聆风学习资料网

ARTICLE · 1179132

Thread源码-jdk21

Thread源码-jdk21
一、Thread概述

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 Thread    permits VirtualThread, ThreadBuilders.BoundVirtualThread
- `BaseVirtualThread`:密封抽象父类,JDK 内部,外部禁止继承

- `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;    }}
- `final ThreadGroup group`:线程组
- `final Runnable task`:执行任务 target
- `final long stackSize`:栈大小
- `volatile int priority`:优先级
- `volatile boolean daemon`:是否守护线程
- `volatile int threadStatus`:线程状态码(JVM 使用)
注:为什么会出现这个内部类, 主要原因是jdk21 引入了虚拟线程, 平台线程所需的属性虚拟线程不需要, 因此为了区分平台线程与虚拟线程,也为了节省内存开销,将平台线程所需的公共属性抽取出来,形成了FieldHolder,虚拟线程这个实例是空的。

四、构造方法

// 空构造,名字自动生成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()` 构建器创建。

Thread.ofVirtual().name("vt-1").start(() -> { ... });
五、核心方法源码解读
1. start()
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(); 
2. run()
@Overridepublic void run() {    Runnable task = holder.task;    if (task != null) {        Object bindings = scopedValueBindings();        runWith(bindings, task);    }}
- 获取当前线程的ScopedValue绑定上下文。
- ScopedValue:JDK21 正式推出,结构化并发`StructuredTaskScope`配套,用来安全传递上下文,替代 ThreadLocal;
- `bindings` 保存作用域内的上下文键值对,支持子线程继承父线程的 ScopedValue。
runWith(bindings, task):核心方法,携带 ScopedValue 上下文去执行 Runnable 任务。内部作用:把拿到的`bindings`绑定到当前线程的作用域,然后执行`task.run()`;任务执行完成之后,自动撤销这个上下文绑定。
@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);}
3.sleep()
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) {           //如果是虚拟线程, 开启虚拟线程的sleep		    		    vthread.sleepNanos(nanos);	} else {           //如果是普通线程,直接调用本地方法	    sleep0(nanos);	}    } finally {	afterSleep(event);    }}//本地方法,让当前线程进入 `TIMED_WAITING`,不释放锁//收到中断信号抛出 `InterruptedException`,并清除中断标记。 private static native void sleep0(long nanos) throws InterruptedException;
4.interrupt() / isInterrupted() / interrupted()
//给线程打中断标记,不是立刻终止线程。//当线程被 `thread.interrupt()` 时,NIO 底层阻塞 IO 对象要执行的回调:中断这个阻塞在当前 IO 上的线程 t,//关闭通道、唤醒阻塞 native 调用,抛出`ClosedByInterruptException`public void interrupt() {    if (this != Thread.currentThread()) {         checkAccess();         // thread may be blocked in an I/O operation         synchronized (interruptLock) { // 中断锁            Interruptible b = nioBlocker;            if (b != null) {	        interrupted = true;  // 设置中断标识                interrupt0();  // inform VM of interrupt 	        b.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;}
5.isAlive()
// 判断当前线程是否存活public final boolean isAlive() {    return alive();}boolean alive() {    return eetop != 0; // 通过此标识判断os线程是否存活}
6、join()
// 永久等待,直到目标线程终止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:无限等待,只要目标线程存活,就一直wait          while (isAlive()) {	      wait(0);	  }	}    }}
注:join()让当前调用线程阻塞,等待目标线程执行完毕之后,当前线程才继续往下执行。是谁调用 join,谁就等待目标线程,不是目标线程等待别人。
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("====主线程执行完=====");}
注:t.join()含义:以`t`作为目标对象,让【当前正在执行这行代码的线程】等待`t`结束。
join的核心原理:基于 Object.wait () + 锁
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核心要点:
join的核心要点:
1.join 底层是 wait,会释放锁,wait()会释放目标 Thread 对象的 monitor 锁;sleep 不会释放任何锁。2. 会抛出 InterruptedException,等待过程中,如果当前等待线程被 interrupt,直接抛异常,中断标记会被清除。3.虚假唤醒,为什么要用`while(isAlive())`而不是 if,因为 wait 存在虚假唤醒(不需要 notify 也可能被唤醒),唤醒后必须再次校验条件,防止提前退出。4.超时版本:等待指定时间,不管目标线程有没有结束,超时后直接返回
平台线程 vs 虚拟线程:join 行为(JDK21)
`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()`
线程启动后-计算机底层完整的运行流程:
平台线程(Platform Thread):1:1 模型,1 个 Java 线程 ↔ 1 个 OS 内核线程
阶段 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.各状态说明
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。
2.状态转换图
                      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
3.触发状态变化的方法对照表
方法
进入状态
唤醒方式
是否释放锁
是否可中断

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

不释放

不可中断

4.各状态的 OS 层面映射

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。

八、VirtualThread 虚拟线程

1.虚拟线程介绍

虚拟线程,M:N 映射,用户态轻量线程,不直接绑定 OS 内核线程。

虚拟线程是JVM 管理的轻量线程,多个虚拟线程复用少量平台线程(载体 Carrier);遇到 JDK 内置阻塞操作时自动 unmount 卸载,载体线程释放,去执行其他虚拟线程;阻塞不占用 OS 内核线程,适合 IO 密集高并发,可以创建百万级别。
2.   VirtualThread 源码
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 continuation    private 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 VM    private 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 时为 null    private 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_PARKING    private volatile Future<?> timeoutTask;//作用:超时定时任务句柄,parkNanos 时向 UNPARKER 提交,提前唤醒时可 cancel    private 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::runContinuation        super(name, characteristics, false);//作用:调用父类构造,虚拟线程始终为 daemon        this.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 参数与默认名称生成    @Override    void 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);//作用:终止后清理            }        }    }    @Override    public void run() {//作用:委托给 Continuation.run(),直接调用不执行用户任务        cont.run();//作用:触发延续体运行    }    private void runContinuation() {//作用:Continuation 的执行体,在载体线程上执行        try {            task.run();//作用:执行用户任务        } finally {            afterTask();//作用:任务完成后清理        }    }    private void afterTask() {//作用:任务完成或异常后的清理,发出 VirtualThreadEndEvent JFR 事件、从容器移除、setState(TERMINATED)、清理引用    @ChangesCurrentThread    @ReservedStackAccess    private 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    @ReservedStackAccess    private void unmount() {//作用:将虚拟线程从载体线程卸载        Thread carrier = Thread.currentCarrierThread();//作用:获取当前载体线程        carrier.setCurrentThread(carrier);//作用:先恢复 Thread.currentThread()        synchronized (interruptLock) {//作用:同步锁            CARRIER_THREAD.setRelease(this, null);//作用:清空载体线程引用        }        carrier.clearInterrupt();//作用:清除载体线程中断        endTransition(false);//作用:结束状态转换    }    @ChangesCurrentThread    private void switchToCarrierThread() {//作用:临时切换到载体线程上下文,用于提交任务、执行特殊逻辑    @ChangesCurrentThread    private 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) {//作用:pinning            long deadline = startTime + nanos;            if (deadline < 0L) deadline = Long.MAX_VALUE;//作用:溢出保护            parkOnCarrierThread(true, deadline - System.nanoTime());//作用:载体线程定时 park        }    }    private void doPark() {//作用:pinning 场景下的无限期 park,委托给 parkOnCarrierThread    private 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 事件    }    @ChangesCurrentThread    void unpark() {//作用:唤醒虚拟线程        Thread currentThread = Thread.currentThread();//作用:获取当前线程        if (!getAndSetParkPermit(true) && currentThread != this) {//作用:原子设置许可            int s = state();//作用:读取状态            if (s == PARKED && compareAndSetState(PARKED, RUNNABLE)) {//作用:CAS PARKED→RUNNABLE                if (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)    @Hidden    private 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 期间已有 unpark                lazySubmitRunContinuation();//作用:懒提交            }        } 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 {//作用:虚拟线程 sleep        if (nanos <= 0) return;        if (Thread.interrupted()) throw new InterruptedException();//作用:先检查中断        setState(TIMED_PARKING);//作用:设置定时挂起        boolean yielded = yieldContinuation();//作用:尝试冻结栈帧        if (!yielded) {//作用:pinning            long 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 事件    @ChangesCurrentThread    private Future<?> scheduleUnpark(long nanos) {//作用:向 UNPARKER 提交超时唤醒任务        Thread carrier = this.carrierThread;        carrier.setCurrentThread(carrier);//作用:切换到载体线程        try {            return UNPARKER.schedule(() -> unpark(), nanos, NANOSECONDS);//作用:提交延迟唤醒        } finally {            carrier.setCurrentThread(this);//作用:恢复虚拟线程        }    }    @ChangesCurrentThread    private 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() {//作用:读取当前状态    @Override    public void interrupt() {//作用:中断虚拟线程        if (state() == TERMINATED) return;//作用:已终止直接返回        synchronized (interruptLock) {            interrupted = true;//作用:设置中断标志        }        if (state() == PARKED) {//作用:已挂起            unpark();//作用:唤醒虚拟线程        }    }    boolean isInterrupted() {//作用:返回中断状态    static boolean interrupted() {//作用:返回并清除当前虚拟线程中断状态    @Override    public void join() throws InterruptedException {//作用:等待虚拟线程终止    @Override    public void join(long millis) throws InterruptedException {//作用:带超时的 join    private 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 绑定等引用,帮助 GC    private 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 字段的锁对象    @Override    public 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    }    @Override    public 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}
3.虚拟线程运行原理说明
3.1.设计思想
虚拟线程的本质是把 Java 栈帧从操作系统线程栈搬到堆内存,从而实现:
i.一个平台线程(载体线程)可以轮流执行成千上万个虚拟线程。
ii.虚拟线程阻塞时不占用 OS 线程,只占用堆内存。
iii虚拟线程的创建、销毁成本极低(无需系统调用)。
iv.这依赖于两个底层原语:Continuation(栈帧冻结/恢复)和 CarrierThread(载体线程)。
3.2.核心组件
组件
职责

Continuation

冻结当前虚拟线程的 Java 栈帧到堆上的 StackChunk,或从 StackChunk 恢复回栈

CarrierThread

真正干活的平台线程,从 ForkJoinPool 取出虚拟线程任务执行

ForkJoinPool

默认调度器,维护 CarrierThread 线程池,负责把 runContinuation 分派给空闲载体线程

UNPARKER

独立平台线程池,处理 parkNanos/sleepNanos 的定时唤醒

VTHREAD_SCOPE

ContinuationScope,标识"这是虚拟线程的延续体",供 yield 判断冻结边界

4.完整执行链路
4.1.创建与启动
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
注:虚拟线程创建时并没有真正的 OS 线程,只是一个 Java 对象 + 一个 Continuation。执行它的任务被丢进 ForkJoinPool 的队列。
4.2.首次挂载执行
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() 返回的是虚拟线程,而不是载体线程。

4.3.遇到阻塞(以 park 为例)
task 内部调用 LockSupport.park()  → VirtualThread.park()      → setState(PARKING)                          // 标记:正在尝试挂起      → yieldContinuation()          → Continuation.yield(VTHREAD_SCOPE)      // VM 原语,尝试冻结栈帧              → [VM] freeze 栈帧 → StackChunk 对象(堆上)              → unmount()                          // 卸载:恢复 Thread.currentThread()              → 控制权返回载体线程      → afterYield()  [由载体线程执行]          → setState(PARKED)                       // 状态推进:已挂起          → 检查 parkPermit                        // 若期间有 unpark 到达,立即重提交
栈帧冻结:Continuation.yield 把当前虚拟线程从 yield 点向上的所有 Java 栈帧复制到堆上的 StackChunk 对象里,然后让载体线程从虚拟线程栈中"弹出"。载体线程此时完全空闲,可以立即去执行别的虚拟线程。
卸载:unmount 把 Thread.currentThread() 恢复为载体线程,清空 carrierThread 引用,清除中断标志,准备迎接下一个虚拟线程。
4.4.被唤醒
另一个线程调用 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(钉住)问题

什么时候 pinning:
当 Continuation.yield 无法冻结栈帧时会发生pinning。
什么原因:
synchronized 块/方法:ObjectMonitor 的 enter/exit 在 VM 内部用 C++ 帧实现,无法序列化到 StackChunk
JNI 调用:Native 方法的栈帧由 C/C++ 管理,VM 无法序列化
Object.wait():与 synchronized 相关,同样涉及 ObjectMonitor
后果:虚拟线程无法卸载,载体线程被阻塞,M:N 调度退化为 1:1。
处理路径:
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字段+映射

相关学习资料

暂无相关学习资料