虚拟线程 - VirtualThread源码透视( 四 )


虚拟线程 - VirtualThread源码透视

文章插图
然后编写和运行下面的例子:
import jdk.internal.vm.Continuation;import jdk.internal.vm.ContinuationScope;public class ContinuationDemo {    public static void main(String[] args) {        ContinuationScope scope = new ContinuationScope("scope");        Continuation continuation = new Continuation(scope, () -> {            System.out.println("Running before yield");            Continuation.yield(scope);            System.out.println("Running after yield");        });        System.out.println("First run");        // 第一次执行Continuation.run        continuation.run();        System.out.println("Second run");        // 第二次执行Continuation.run        continuation.run();        System.out.println("Done");    }}// 运行代码,神奇的结果出现了First runRunning before yieldSecond runRunning after yieldDone这里可以看出Continuation的奇妙之处,Continuation实例进行yield调用后,再次调用其run方法就可以从yield的调用之处往下执行,从而实现了程序的中断和恢复 。
源码分析主要包括:
  • Continuation
  • VirtualThread
  • 线程建造器
ContinuationContinuation直译为"连续",一般来说表示一种语言构造,使语言可以在任意点保存执行状态并且在之后的某个点返回 。在JDK中对应类jdk.internal.vm.Continuation,这个类只有一句类注释A one-shot delimited continuation,直译为一个只能执行一次的回调函数 。由于Continuation的成员和方法缺少详细的注释,并且大部分功能由JVM实现,这里只能阅读其一些骨干源码和上一小节编写的Continuation相关例子去了解其实现(笔者C语言比较薄弱,有兴趣的可以翻阅JVM的源码) 。先看成员变量和构造函数:
// 判断是否需要保留当前线程的本地缓存,由系统参数jdk.preserveExtentLocalCache决定private static final boolean PRESERVE_EXTENT_LOCAL_CACHE;// 真正要被执行的任务实例private final Runnable target;// 标识Continuation的范围,private final ContinuationScope scope;// Continuation的父节点,如果为空的时候则为本地线程栈private Continuation parent;// Continuation的子节点,非空时候说明在子Continuation中进行了yield操作private Continuation child;// 猜测为Continuation栈结构,由JVM管理,无法得知其真实作用private StackChunk tail;// 标记Continuation是否已经完成private boolean done;// 标记是否进行了mount操作private volatile boolean mounted = false;// yield操作时候设置的信息private Object yieldInfo;// 标记一个未挂载的Continuation是否通过强制抢占式卸载private boolean preempted;// 保留当前线程的本地缓存的副本private Object[] extentLocalCache;// 构造函数,要求传入范围和任务包装实例public Continuation(ContinuationScope scope, Runnable target) {    this.scope = scope;    this.target = target;}

经验总结扩展阅读