我们之前使用的是操作系统平台的线程,就称之为“系统线程”吧。虚拟线程是JDK维护的,原理跟WebFlux的底层实现差不多,都是工作线程分离。

要使用虚拟线程,需要使用JDK21以上,包括21。

虚拟线程可以创建很多很多

系统线程不能轻易创建太多,我们一直被教导创建线程是很重的活动。

        for (int i = 0; i < 1_000_000; i++) {
new Thread(() -> {
longAdder.increment();
System.out.println(longAdder.longValue());
try {
Thread.sleep(10000);
} catch (Exception e) {
// deal with e
}
}).start();
}

上面尝试创建百万个线程,线程都会休眠不结束。我用了一个LongAdder记录我的笔记本能实际创建多少线程。结果是4000多个,用了6秒:



改成虚拟线程就轻松成功:

        LongAdder longAdder = new LongAdder();
for (int i = 0; i < 1_000_000; i++) {
Thread.ofVirtual().start(() -> {
longAdder.increment();
System.out.println(longAdder.longValue());
try {
Thread.sleep(100000);
} catch (Exception e) {
// deal with e
}
});
}

因为虚拟线程很轻量,所以不要使用线程池,可以很轻易的创建很多个。因为能创建很多,所以也不要使用 Thread Local 变量。

IO操作不好阻塞虚拟线程的使用

使用系统线程,必须通过线程池来处理多个任务,不然问题很严重:

    static void callService(String taskName) {
try {
System.out.println(Thread.currentThread() + " executing " + taskName);
new URL("自己写一个http接口?sleep=2000").getContent();
System.out.println(Thread.currentThread() + " completed " + taskName); } catch (Exception e) {
// deal with e
}
} try (ExecutorService executor = Executors.newFixedThreadPool(5)) {
for (int i = 0; i <= 10; i++) {
String taskName = "Task" + i;
executor.execute(() -> callService(taskName));
}
}

执行的时候你能看到,线程在执行结束前需要空闲等待任务的IO。毕竟每个任务都是在某一个线程上执行 —— 说这个干啥?

看一下虚拟线程

        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i <= 600; i++) {
String taskName = "Task" + i;
executor.execute(() -> callService(taskName));
}
}

这里创建了一个虚拟线程工厂(而不是线程池,记住不要使用虚拟化的线程池),它会给每个任务创建新的虚拟线程。

程序启动后,会立即打印600个"executing",而不是像系统线程那样只打印5个。

为了方便,我们少用几个任务来实验看一下输出:

VirtualThread[#50]/runnable@ForkJoinPool-1-worker-2 executing Task1
VirtualThread[#48]/runnable@ForkJoinPool-1-worker-1 executing Task0
VirtualThread[#51]/runnable@ForkJoinPool-1-worker-3 executing Task2
VirtualThread[#51]/runnable@ForkJoinPool-1-worker-2 completed Task2
VirtualThread[#48]/runnable@ForkJoinPool-1-worker-3 completed Task0
VirtualThread[#50]/runnable@ForkJoinPool-1-worker-1 completed Task1

仔细看,这里一共3个虚拟线程,因为工厂创建了三个,根据任务数来的。

但是每个任务都是在两个虚拟线程上:Task1 被worker-2接收,却被worker-1完成。

啥时候用

关键问题来了,我们总该使用虚拟线程吗?

对各种问题都通用的答案是:你没遇到问题就别想着解决问题。

如果的确有问题,想看看虚拟线程是否合适,可以看一下任务是否是IO密集型的。

对于计算密集型任务,系统线程比虚拟线程有效得多。

虚拟线程跟WebFlux一样,只能提升系统的吞吐量,并不能加快单个任务的完成时间。

Java21的虚拟线程Virtual Thread初体验的更多相关文章

  1. 线程池(ExecutorService)初体验

    背景:查询月统计数据,因为查询日统计数据功能已经实现.月统计数据,只是参一个List(date) 参数,for循环调用日统计,然后把结果整合就OK. 问题:单线程跑  太耗时间 解决方案:使用多线程, ...

  2. Java19虚拟线程都来了,我正在写的线程代码会被淘汰掉吗?

    Java19中引入了虚拟线程,虽然默认是关闭的,但是可以以Preview模式启用,这绝对是一个重大的更新,今天Java架构杂谈带大家开箱验货,看看这家伙实现了什么了不起的功能. 1 为什么需要虚拟线程 ...

  3. Java的虚拟线程(协程)特性开启预览阶段,多线程开发的难度将大大降低

    高并发.多线程一直是Java编程中的难点,也是面试题中的要点.Java开发者也一直在尝试使用多线程来解决应用服务器的并发问题.但是多线程并不容易,为此一个新的技术出现了,这就是虚拟线程. 传统多线程的 ...

  4. Java SE 19 虚拟线程

    Java SE 19 虚拟线程 作者:Grey 原文地址: 博客园:Java SE 19 虚拟线程 CSDN:Java SE 19 虚拟线程 说明 虚拟线程(Virtual Threads)是在Pro ...

  5. 虚拟线程 - VirtualThread源码透视

    前提 JDK19于2022-09-20发布GA版本,该版本提供了虚拟线程的预览功能.下载JDK19之后翻看了一下有关虚拟线程的一些源码,跟早些时候的Loom项目构建版本基本并没有很大出入,也跟第三方J ...

  6. 数据结构(逻辑结构,物理结构,特点) C#多线程编程的同步也线程安全 C#多线程编程笔记 String 与 StringBuilder (StringBuffer) 数据结构与算法-初体验(极客专栏)

    数据结构(逻辑结构,物理结构,特点) 一.数据的逻辑结构:指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后件关系,而与他们在计算机中的存储位置无关.逻辑结构包括: 集合 数 ...

  7. 支持JDK19虚拟线程的web框架,之一:体验

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于虚拟线程 随着JDK19 GA版本的发布,虚拟线程 ...

  8. Scala 深入浅出实战经典 第66讲:Scala并发编程实战初体验

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  9. 算法学习:并行化初体验_JAVA实现并行化归并算法

    这个系列包括算法导论学习过程的记录. 最初学习归并算法,对不会使其具体跑在不同的核上报有深深地怨念,刚好算倒重温了这个算法,闲来无事,利用java的thread来体验一下并行归并算法.理论上开的thr ...

  10. 【Spark深入学习 -15】Spark Streaming前奏-Kafka初体验

    ----本节内容------- 1.Kafka基础概念 1.1 出世背景 1.2 基本原理 1.2.1.前置知识 1.2.2.架构和原理 1.2.3.基本概念 1.2.4.kafka特点 2.Kafk ...

随机推荐

  1. 10-flask博客项目

    centos7 编译安装python3.7.1 安装步骤 centos7自带python2,由于执行yum需要python2,所以即使安装了python3也不能删除python21.安装依赖包yum ...

  2. Java中CAS算法的集中体现:Atomic原子类库,你了解吗?

    一.写在开头 在前面的博文中我们学习了volatile关键字,知道了它可以保证有序性和可见性,但无法保障原子性,结局原子性问题推荐使用synchronized.Lock或者AtomicInteger: ...

  3. 一个问题:六位八段数码管(Verilog)

    [基本信息] 需求:verilog程序,显示任意六位字符或数值,包含点号,且能够按需点亮位数.(学习篇) 芯片型号:cyclone Ⅳ EP4CE10F17C8 数码管属性:六位.八段 [最终成果图] ...

  4. 15种pod的状态

    15种pod的状态 调度失败 常见错误状态(Unschedulable) pod被创建后进入调度阶段,k8s调度器依据pod声明的资源请求量和调度规则,为pod挑选一个适合运行的节点.当集群节点不满足 ...

  5. openstack neutron 报错

    openstack neutron /etc/neutron下面没有dhcp文件 查错发现安装时候打错

  6. NET8中增加的简单适用的DI扩展库Microsoft.Extensions.DependencyInjection.AutoActivation

    这个库提供了在启动期间实例化已注册的单例,而不是在首次使用它时实例化. 单例通常在首次使用时创建,这可能会导致响应传入请求的延迟高于平时.在注册时创建实例有助于防止第一次Request请求的SLA 以 ...

  7. 使用POST方法向网站发送数据

    POST方法向网站发送数据 server.py import flask app = flask.Flask(__name__) @app.route('/', methods=['GET','POS ...

  8. ODPS 不用循环生成连续日期

    生成 20230801 ~ 20230831之间的每一天的sql代码怎么写? 只要一行代码. 一行代码: select TO_CHAR(DATEADD(TO_DATE(bizdate,'yyyymmd ...

  9. 4.4K Star!推荐一款新一代的极简监控系统!轻量高性能!超500个监控指标,颜值高、功能强大!

    在信息化快速发展的今天,企业运维面临的挑战日益增多.传统的运维监控系统往往存在功能冗余.性能低下.操作复杂等问题,难以满足现代企业对高效.稳定.智能的运维管理需求. 今天给大家推荐一款新一代极简运维监 ...

  10. Ubuntu禁止和启动内核更新

    ubuntu禁止和启动内核更新 https://www.cnblogs.com/passedbylove/p/13091002.html https://www.cnblogs.com/sparkde ...