虚拟线程 - VirtualThread源码透视

前提JDK19于2022-09-20发布GA版本,该版本提供了虚拟线程的预览功能 。下载JDK19之后翻看了一下有关虚拟线程的一些源码,跟早些时候的Loom项目构建版本基本并没有很大出入,也跟第三方JDK如鹅厂的Kona虚拟线程实现方式基本一致,这里分析一下虚拟线程设计与源码实现 。
Platform Thread与Virtual Thread因为引入了虚拟线程,原来JDK存在java.lang.Thread类,俗称线程,为了更好地区分虚拟线程和原有的线程类,引入了一个全新类java.lang.VirtualThread(Thread类的一个子类型),直译过来就是"虚拟线程" 。

  • 题外话:在Loom项目早期规划里面,核心API其实命名为Fiber,直译过来就是"纤程"或者"协程",后来成为了废案,在一些历史提交的Test类或者文档中还能看到类似于下面的代码:
// java.lang.FiberFiber f = Fiber.execute({    out.println("Good morning");    readLock.lock();    try{        out.println("Good night");    } finally{        readLock.unlock();    }    out.println("Good night");});Thread在此基础上做了不少兼容性工作 。此外,还应用了建造者模式引入了线程建造器,提供了静态工厂方法Thread#ofPlatform()和Thread#ofVirtual()分别用于实例化Thread(工厂)建造器和VirtualThread(工厂)建造器,顾名思义,两种建造器分别用于创建Thread或者VirtualThread,例如:
// demo-1 build platform threadThread platformThread = Thread.ofPlatform().daemon().name("worker").unstarted(runnable);// demo-2 create platform thread factoryThreadFactory platformThreadFactory = Thread.ofPlatform().daemon().name("worker-", 0).factory();// demo-3 build virtual threadThread virtualThread = Thread.ofVirtual().name("virtual-worker").unstarted(runnable);// demo-4 create virtual thread factoryThreadFactory virtualThreadFactory = Thread.ofVirtual().name("virtual-worker-", 0).factory();更新的JDK文档中也把原来的Thread称为Platform Thread,可以更明晰地与Virtual Thread区分开来 。这里Platform Thread直译为"平台线程",其实就是"虚拟线程"出现之前的老生常谈的"线程" 。
后文会把Platform Thread称为平台线程,Virtual Thread称为虚拟线程,或者直接用其英文名称
那么平台线程与虚拟线程的联系和区别是什么?JDK中的每个java.lang.Thread实例也就是每个平台线程实例都在底层操作系统线程上运行Java代码,并且平台线程在运行代码的整个生命周期内捕获系统线程 。可以得出一个结论,平台线程与底层系统线程是一一对应的,平台线程实例本质是由系统内核的线程调度程序进行调度,并且平台线程的总数量受限于系统线程的总数量 。
虚拟线程 - VirtualThread源码透视

文章插图
总的来说,平台线程有下面的一些特点或者说限制:
  • 资源有限导致系统线程总量有限,进而导致与系统线程一一对应的平台线程有限
  • 平台线程的调度依赖于系统的线程调度程序,当平台线程创建过多,会消耗大量资源用于处理线程上下文切换
  • 每个平台线程都会开辟一块私有的栈空间,大量平台线程会占据大量内存
这些限制导致开发者不能极大量地创建平台线程,为了满足性能需要,需要引入池化技术、添加任务队列构建消费者-生产者模式等方案去让平台线程适配多变的现实场景 。显然,开发者们迫切需要一种轻量级线程实现,刚好可以弥补上面提到的平台线程的限制,这种轻量级线程可以满足:

经验总结扩展阅读