- 可以大量创建,例如十万级别、百万级别,而不会占据大量内存
- 由JVM进行调度和状态切换,并且与系统线程"松绑"
- 用法与原来平台线程差不多,或者说尽量兼容平台线程现存的API
文章插图
当然,平台线程不是简单地与虚拟线程进行1:N的绑定,后面的章节会深入分析虚拟线程的运行原理 。
虚拟线程实现原理虚拟线程是一种轻量级(用户模式)线程,这种线程是由Java虚拟机调度,而不是操作系统 。虚拟线程占用空间小,任务切换开销几乎可以忽略不计,因此可以极大量地创建和使用 。总体来看,虚拟线程实现如下:
virtual thread = continuation + scheduler虚拟线程会把任务(一般是java.lang.Runnable)包装到一个Continuation实例中:
- 【虚拟线程 - VirtualThread源码透视】当任务需要阻塞挂起的时候,会调用Continuation的yield操作进行阻塞
- 当任务需要解除阻塞继续执行的时候,Continuation会被继续执行
- 执行器是java.util.concurrent.Executor的子类
- 虚拟线程框架提供了一个默认的ForkJoinPool用于执行虚拟线程任务
下文会把carrier thread称为"载体线程",指的是负责执行虚拟线程中任务的平台线程,或者说运行虚拟线程的平台线程称为它的载体线程操作系统调度系统线程,而Java平台线程与系统线程一一映射,所以平台线程被操作系统调度,但是虚拟线程是由JVM调度 。JVM把虚拟线程分配给平台线程的操作称为mount(挂载),反过来取消分配平台线程的操作称为unmount(卸载):
- mount操作:虚拟线程挂载到平台线程,虚拟线程中包装的Continuation栈数据帧或者引用栈数据会被拷贝到平台线程的线程栈,这是一个从堆复制到栈的过程
- unmount操作:虚拟线程从平台线程卸载,大多数虚拟线程中包装的Continuation栈数据帧会留在堆内存中
mount();try { Continuation.run();} finally { unmount();}从Java代码的角度来看,虚拟线程和它的载体线程暂时共享一个OS线程实例这个事实是不可见,因为虚拟线程的堆栈跟踪和线程本地变量与平台线程是完全隔离的 。JDK中专门是用了一个FIFO模式的ForkJoinPool作为虚拟线程的调度程序,从这个调度程序看虚拟线程任务的执行流程大致如下:
- 调度器(线程池)中的平台线程等待处理任务
文章插图
- 一个虚拟线程被分配平台线程,该平台线程作为运载线程执行虚拟线程中的任务
文章插图
- 虚拟线程运行其Continuation,从而执行基于Runnable包装的用户任务
文章插图
- 虚拟线程任务执行完成,标记Continuation终结,标记虚拟线程为终结状态,清空一些上下文变量,运载线程"返还"到调度器(线程池)中作为平台线程等待处理下一个任务
经验总结扩展阅读
- 第一篇 TTD 专题 :C# 那些短命线程都在干什么?
- Java并发编程 | 从进程、线程到并发问题实例解决
- 七 Netty 学习:NioEventLoop 对应线程的创建和启动源码说明
- 云原生虚拟网络 tun/tap & veth-pair
- 补充部分---ScheduledThreadPoolExecutor类分析 线程池底层原理详解与源码分析
- 附Anaconda安装包 Anaconda安装和卸载+虚拟环境Tensorflow安装以及末尾问题大全,这一篇就够了!!!
- 虚拟发货怎么确认收货
- 建议收藏 Java线程同步的四种方式详解
- 用AR Engine手部骨骼跟踪能力实现虚拟手表试戴
- 通过Thread Pool Executor类解析线程池执行任务的核心流程