Java SE 19 虚拟线程
Java SE 19 虚拟线程
作者:Grey
原文地址:
说明
虚拟线程(Virtual Threads)是在Project Loom中开发的,并从 Java SE 19 开始作为预览功能引入 JDK。
在线程模型下,一个 Java 线程相当于一个操作系统线程,而这些线程是很消耗资源的,如果启动的线程过多,会给整个系统的稳定性带来风险。
虚拟线程解决了这个问题,从 Java 代码的角度来看,虚拟线程感觉就像普通的线程,但它们不是 1:1
地映射到操作系统线程上。
有一个所谓的载体线程池,一个虚拟线程被临时映射到该池中。一旦虚拟线程遇到阻塞操作,该虚拟线程就会从载体线程中移除,而载体线程可以执行另一个虚拟线程(新的或之前被阻塞的)。
所以阻塞的操作不再阻塞执行的线程。这使得我们可以用一个小的载体线程池来并行处理大量的请求。
示例
场景
启动 1000 个任务,每个任务等待一秒钟(模拟访问外部API),然后返回一个结果(在这个例子中是一个随机数)。
任务类如下
package git.snippets.vt;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadLocalRandom;
/**
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/21
* @since 19
*/
public class Task implements Callable<Integer> {
private final int number;
public Task(int number) {
this.number = number;
}
@Override
public Integer call() {
System.out.printf("Thread %s - Task %d waiting...%n", Thread.currentThread().getName(), number);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.printf("Thread %s - Task %d canceled.%n", Thread.currentThread().getName(), number);
return -1;
}
System.out.printf("Thread %s - Task %d finished.%n", Thread.currentThread().getName(), number);
return ThreadLocalRandom.current().nextInt(100);
}
}
接下来,我们测试使用线程池开启 100 个线程处理 1000 个任务需要多长时间。
package git.snippets.vt;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/21
* @since 19
*/
public class App {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(100);
List<Task> tasks = new ArrayList<>();
for (int i = 0; i < 1_000; i++) {
tasks.add(new Task(i));
}
long time = System.currentTimeMillis();
List<Future<Integer>> futures = executor.invokeAll(tasks);
long sum = 0;
for (Future<Integer> future : futures) {
sum += future.get();
}
time = System.currentTimeMillis() - time;
System.out.println("sum = " + sum + "; time = " + time + " ms");
executor.shutdown();
}
}
运行结果如下
Thread pool-1-thread-1 - Task 0 waiting...
Thread pool-1-thread-3 - Task 2 waiting...
Thread pool-1-thread-2 - Task 1 waiting...
……
sum = 49879; time = 10142 ms
接下来,我们用虚拟线程测试整个事情。因此,我们只需要替换这一行
ExecutorService executor = Executors.newFixedThreadPool(100);
替换为
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
执行效果如下
Thread - Task 0 waiting...
Thread - Task 2 waiting...
Thread - Task 3 waiting...
……
sum = 48348; time = 1125 ms
1125 ms
VS 10142 ms
,性能提升非常明显。
注:本示例需要在 JDK 19 下运行,且需要增加 --enable-preview
参数,在 IDEA 下,这个参数配置如下
我们已经了解了创建虚拟线程的一种方法:使用Executors.newVirtualThreadPerTaskExecutor()
创建的执行器服务,为每个任务创建一个新的虚拟线程。
使用Thread.startVirtualThread()
或Thread.ofVirtual().start()
,我们也可以明确地启动虚拟线程。
Thread.startVirtualThread(() -> {
// code to run in thread
});
Thread.ofVirtual().start(() -> {
// code to run in thread
});
特别说明:Thread.ofVirtual()
返回一个VirtualThreadBuilder
,其start()
方法启动一个虚拟线程。另一个方法Thread.ofPlatform()
返回一个PlatformThreadBuilder
,通过它我们可以启动一个平台线程。
这两种构造方法都实现了Thread.Builder
接口。这使得我们可以编写灵活的代码,在运行时决定它应该在虚拟线程还是平台线程中运行。
源码
参考资料
Java 19 Features (with Examples)
Virtual Threads in Java (Project Loom)
Java SE 19 虚拟线程的更多相关文章
- Java SE 19 新增特性
Java SE 19 新增特性 作者:Grey 原文地址: 博客园:Java SE 19 新增特性 CSDN:Java SE 19 新增特性 源码 源仓库: Github:java_new_featu ...
- Java将增加虚拟线程,挑战Go协程
我们知道 Go 语言最大亮点之一就是原生支持并发,这得益于 Go 语言的协程机制.一个 go 语句就可以发起一个协程 (goroutin).协程本质上是一种用户态线程,它不需要操作系统来进行调度,而是 ...
- Java SE (5)之 线程使用
JAVA有两种线程的方法Thread 和Runnable 能够使用,这是为了弥补不能多继承的缺陷 首先是 Thread package com.sunzhiyan03; /* * 演示线程 * */ ...
- java SE学习之线程同步(详细介绍)
java程序中可以允许存在多个线程,但在处理多线程问题时,必须注意这样一个问题: 当两个或多个线程同时访问同一个变量,并且一些线程需要修改这个变量时,那么这个 ...
- 19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...
- Java的虚拟线程(协程)特性开启预览阶段,多线程开发的难度将大大降低
高并发.多线程一直是Java编程中的难点,也是面试题中的要点.Java开发者也一直在尝试使用多线程来解决应用服务器的并发问题.但是多线程并不容易,为此一个新的技术出现了,这就是虚拟线程. 传统多线程的 ...
- Java SE教程
第0讲 开山篇 读前介绍:本文中如下文本格式是超链接,可以点击跳转 >>超链接<< 我的学习目标:基础要坚如磐石 代码要十份规范 笔记要认真详实 一.java内容介绍 ...
- 【译】Java SE 14 Hotspot 虚拟机垃圾回收调优指南
原文链接:HotSpot Virtual Machine Garbage Collection Tuning Guide,基于Java SE 14. 本文主要包括以下内容: 优化目标与策略(Ergon ...
- 【读书笔记】《写给大忙人看的Java SE 8》——Java8新特性总结
虽然看过一些Java 8新特性的资料,但是平时很少用到,时间长了就忘了,正好借着Java 9的发布,来总结下一些Java 8中的新特性. 接口中的默认方法和静态方法 先考虑一个问题,如何向Java中的 ...
随机推荐
- 05 MySQL_主键约束
主键约束 主键: 用于表示数据唯一性的字段称为主键: 约束:就是对表字段添加限制条件 主键约束:保证主键字段的值唯一且非空: - 格式 : create table t1(id int primary ...
- C#Lambda表达式演变和Linq的深度解析
Lambda 一.Lambda的演变 Lambda的演变,从下面的类中可以看出,.Net Framwork1.0时还是用方法实例化委托的,2.0的时候出现了匿名方法,3.0的时候出现了Lambda. ...
- mysql5.7通过文件zip方式安装-九五小庞
为什么通过zip的方式进行安装 电脑上已安装过mysql数据库,想要再安装一个. 1.下载mysql安装包 直接找到mysql官网,在官网上下载zip安装包. https://downloads.my ...
- 使用centos linux vps搭建jupyter notebook踩坑日记
今天我尝试用vps搭建在线jupyter notebook网站时遇到了这样一个问题: [W 21:48:07.243 NotebookApp] SSL Error on 9 ('171.115.101 ...
- DP の 百题大过关(5/100)
动态规划自古以来是DALAO凌虐萌新的分水岭,但有些OIer认为并没有这么重要--会打暴力,大不了记忆化.但是其实,动态规划学得好不好,可以彰显出一个OIerOIer的基本素养--能否富有逻辑地思 ...
- fiddler抓包手机请求(转)
http://ju.outofmemory.cn/entry/22854 从事前端开发的同学一定对Fiddler不陌生,它是一个非常强大的http(s)协议分析工具,如果你不知道它是什么,可以自行go ...
- 蔚来杯2022牛客暑期多校训练营5 ABCDFGHK
比赛链接 A 题解 知识点:图论,dp. 暴力建图,连接所有点的双向通路,除了原点是单向的,并且把路径长度作为权值. 随后,从原点出发(\(f[0] = 0\),其他点负无穷,保证从原点出发),按照权 ...
- vue2与vue3实现响应式的原理区别和提升
区别: vue2.x: 实现原理: 对象类型:Object.defineProperty()对属性的读取,修改进行拦截(数据劫持): 数组类型:通过重写更新数组的一系列方法来进行拦截(对数组的变更方法 ...
- win10+Android(华为)系统原生日历同步方案+Sol日历桌面显示
前言:本文是参考了其他博客基础上,新增了Android的免费桌面[月试图显示]功能.以及适配于上海交通大学的Canvas教学日历.方便进行多设备同步的日历管理.任务提醒. 目录 1.效果展示 2.方案 ...
- 六 抽象工厂模式【Abstract Factory Pattern】 来自CBF4LIFE 的设计模式0
好了,我们继续上一节课,上一节讲到女娲造人,人是造出来了,世界时热闹了,可是低头一看,都是清一色的类型,缺少关爱.仇恨.喜怒哀乐等情绪,人类的生命太平淡了,女娲一想,猛然一拍脑袋,Shit!忘记给人类 ...