当前位置:首页 > 科技  > 软件

提升系统吞吐量,详解JDK21虚拟线程,炸裂

来源: 责编: 时间:2024-06-06 17:36:22 84观看
导读环境:JDK211. 虚拟线程简介虚拟线程是轻量级的线程,可以减少编写、维护和调试高吞吐量并发应用程序的工作量。线程是可以调度的最小处理单元。它与其他类似单元并发运行,而且在很大程度上是独立运行的。它是java.lang.Th

环境:JDK21G9O28资讯网——每日最新资讯28at.com

1. 虚拟线程简介

虚拟线程是轻量级的线程,可以减少编写、维护和调试高吞吐量并发应用程序的工作量。线程是可以调度的最小处理单元。它与其他类似单元并发运行,而且在很大程度上是独立运行的。它是java.lang.Thread的一个实例。线程有两种,平台线程和虚拟线程。G9O28资讯网——每日最新资讯28at.com

2. 什么是平台线程

平台线程被实现为操作系统(OS)线程的薄包装器。平台线程在其底层操作系统线程上运行Java代码,平台线程在平台线程的整个生命周期中捕获其操作系统线程。因此,可用平台线程的数量受限于操作系统线程的数量。G9O28资讯网——每日最新资讯28at.com

平台线程通常有一个比较大的线程堆栈和由操作系统维护的其他资源。它们适用于运行所有类型的任务,但可能是有限的资源。G9O28资讯网——每日最新资讯28at.com

3. 什么是虚拟线程

与平台线程一样,虚拟线程也是java.lang.thread的一个实例。然而,虚拟线程并没有绑定到特定的操作系统线程。虚拟线程仍然在操作系统线程上运行代码。但是,当虚拟线程中运行的代码调用阻塞I/O操作时,Java运行时会挂起虚拟线程,直到可以恢复为止。与挂起的虚拟线程相关联的OS线程现在可以自由地执行其他虚拟线程的操作。G9O28资讯网——每日最新资讯28at.com

虚拟线程的实现方式与虚拟内存类似。为了模拟大量内存,操作系统将大量虚拟地址空间映射到有限的RAM。同样,为了模拟大量线程,Java运行时将大量虚拟线程映射到少量操作系统线程。G9O28资讯网——每日最新资讯28at.com

与平台线程不同,虚拟线程通常有一个浅调用堆栈,只执行一个HTTP客户端调用或一个JDBC查询。尽管虚拟线程支持线程本地变量和可继承的线程本地变量,但应该仔细考虑使用它们,因为单个JVM可能支持数百万个虚拟线程。G9O28资讯网——每日最新资讯28at.com

虚拟线程适用于运行大部分时间被阻塞的任务,这些任务通常等待I/O操作完成。然而,它们并不适用于长时间运行的CPU密集型操作。G9O28资讯网——每日最新资讯28at.com

4. 为什么使用虚拟线程

在高吞吐量并发应用程序中使用虚拟线程,尤其是那些由大量并发任务组成、花费大量时间等待的应用程序。服务器应用程序是高吞吐量应用程序的示例,因为它们通常处理许多执行阻塞I/O操作(如获取资源)的客户端请求。G9O28资讯网——每日最新资讯28at.com

虚拟线程不是更快的线程;它们运行代码的速度并不比平台线程快。它们的存在是为了提供规模(更高的吞吐量),而不是速度(更低的延迟)。G9O28资讯网——每日最新资讯28at.com

5. 创建虚拟线程

Thread和Thread.Builder APIs提供了创建平台线程和虚拟线程的方法。java.util.concurrent.Executors类还定义了创建ExecutorService的方法,该方法为每个任务启动一个新的虚拟线程。G9O28资讯网——每日最新资讯28at.com

5.1 Thread & Thread.Builder创建虚拟线程

调用Thread.ofVirtual()方法创建一个Thread.Builder实例,用于创建虚拟线程。如下示例:G9O28资讯网——每日最新资讯28at.com

Thread t= Thread.ofVirtual().start(() -> System.out.println("Hello")) ;t.join() ;

Thread.Builder接口允许创建具有公共线程属性(如线程名称)的线程。Thread.Builder.OfPlatform子接口创建平台线程,而Thread.Builder.OfVirtual创建虚拟线程。G9O28资讯网——每日最新资讯28at.com

下面的示例使用Thread.Builder接口创建一个名为T-VM的虚拟线程,如下示例:G9O28资讯网——每日最新资讯28at.com

Thread.Builder builder = Thread.ofVirtual().name("T-VM") ;Runnable task = () -> {  System.out.println("执行任务") ;} ;Thread t = builder.start(task) ;System.err.printf("线程名称: %s%n", t.getName()) ;t.join() ;

输出结果:G9O28资讯网——每日最新资讯28at.com

执行任务线程名称T-VM

下面的示例创建并启动两个具有Thread.Builder的虚拟线程:G9O28资讯网——每日最新资讯28at.com

Thread.Builder builder = Thread.ofVirtual().name("vm - worker - ", 0);Runnable task = () -> {  System.out.printf("线程ID: %d%n", Thread.currentThread().threadId());} ;// 线程 "vm - worker - 0"Thread t1 = builder.start(task) ;   t1.join();System.out.println(t1.getName() + " terminated") ;// 线程 "vm - worker - 1"Thread t2 = builder.start(task) ;   t2.join() ;  System.out.println(t2.getName() + " terminated") ;

输出结果:G9O28资讯网——每日最新资讯28at.com

线程ID: 21vm - worker - 0 terminated线程ID: 24vm - worker - 1 terminated

以上是通过Thread.Builder创建虚拟线程的简单示例。G9O28资讯网——每日最新资讯28at.com

5.2 Executors创建虚拟线程

Executors允许将线程管理和创建与应用程序的其余部分分离。G9O28资讯网——每日最新资讯28at.com

ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor() ;// submit Runnable任务Future<?> future = executor.submit(() -> System.out.println("Running thread")) ;future.get() ;System.out.println("Task completed") ;

上面示例每当调用ExecutorService.submit(Runnable)时,都会创建一个新的虚拟线程并开始运行该任务。G9O28资讯网——每日最新资讯28at.com

6. 虚拟线程调度

操作系统在平台线程运行时进行调度。然而,Java运行时会在虚拟线程运行时进行调度。当Java运行时调度虚拟线程时,它将虚拟线程分配或挂载到平台线程上,然后操作系统像往常一样调度该平台线程。这个平台线程称为载体(carrier)。运行一些代码后,虚拟线程可以从它的载体卸载。这通常发生在虚拟线程执行阻塞I/O操作时。当一个虚拟线程从其宿主中卸载后,宿主就处于空闲状态,这意味着Java运行时调度器可以在其上分配另一个虚拟线程。G9O28资讯网——每日最新资讯28at.com

虚拟线程被绑定到其宿主(平台线程)时,在阻塞操作期间无法将其卸载。虚拟线程在以下情况下会被绑定:G9O28资讯网——每日最新资讯28at.com

  • 虚拟线程在同步块或方法内运行代码
  • 虚拟线程运行本机方法或外部函数

7. 虚拟线程应用指南

虚拟线程是由Java运行时而不是操作系统实现的Java线程。虚拟线程和传统线程(平台线程)的主要区别在于,可以很容易地在同一个Java进程中运行大量甚至数百万个活动的虚拟线程。正是它们的数量赋予了虚拟线程强大的能力,通过允许服务器并发处理更多请求,它们可以更高效地运行以"thread-per-request"风格编写的服务器应用程序,从而提高吞吐量,减少硬件浪费。G9O28资讯网——每日最新资讯28at.com

虚拟线程可以显著提高以thread-per-request风格编写的服务器的吞吐量,而不是延迟。在这种风格中,服务器在整个持续时间内使用一个线程来处理每个传入的请求。它至少占用一个线程,因为在处理单个请求时,你可能希望使用更多线程并发地执行某些任务。G9O28资讯网——每日最新资讯28at.com

阻塞平台线程的代价是昂贵的,因为它会占用线程——这是一种相对稀缺的资源——而线程并没有做很多有意义的工作。因为虚拟线程可能很多,所以阻塞它们是廉价的,也是值得鼓励的。因此,应该使用简单的同步风格并使用阻塞I/O API编写代码。G9O28资讯网——每日最新资讯28at.com

如下代码以非阻塞异步风格编写,不会从虚拟线程中获得太多好处。G9O28资讯网——每日最新资讯28at.com

HttpClient client = ... ;Executor pool = Executors.newVirtualThreadPerTaskExecutor() ;CompletableFuture.supplyAsync(() -> {  HttpRequest request = HttpRequest.newBuilder(URI.create("http://localhost:8088/users/info")).build() ;  BodyHandler<String> bodyHandler = ... ;  try {    return client.send(request , bodyHandler) ;  }}, pool).thenCompose(url -> getBodyAsync(url, HttpResponse.BodyHandlers.ofString())).thenApply(info::findImage).thenAccept(this::process).exceptionally(t -> { t.printStackTrace(); return null; });

相反,以下代码以同步风格编写,并使用简单的阻塞IO,将受益匪浅:G9O28资讯网——每日最新资讯28at.com

try {   String page = getBody(info.getUrl(), HttpResponse.BodyHandlers.ofString());   String imageUrl = info.findImage(page);   byte[] data = getBody(imageUrl, HttpResponse.BodyHandlers.ofByteArray());      info.setImageData(data);   process(info);}

8. 不要池化虚拟线程

关于虚拟线程最难理解的是,虽然它们与平台线程具有相同的行为,但它们不应该表示相同的程序概念。G9O28资讯网——每日最新资讯28at.com

平台线程很少,因此是一种宝贵的资源。宝贵的资源需要管理,管理平台线程的最常见方法是使用线程池。接下来你需要回答的问题是,线程池中应该有多少个线程?G9O28资讯网——每日最新资讯28at.com

但是虚拟线程是很多的,因此每个线程不应该代表某种共享的、池化的资源,而应该代表一个任务。G9O28资讯网——每日最新资讯28at.com

将n个平台线程转换为n个虚拟线程几乎没有好处;相反,需要转换的是任务。G9O28资讯网——每日最新资讯28at.com

为了将每个应用任务表示为一个线程,不要像下面的例子那样使用共享线程池:G9O28资讯网——每日最新资讯28at.com

Future<ResultA> f1 = sharedThreadPoolExecutor.submit(task1);Future<ResultB> f2 = sharedThreadPoolExecutor.submit(task2);// ... use futures

相反,使用虚拟线程G9O28资讯网——每日最新资讯28at.com

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {   Future<ResultA> f1 = executor.submit(task1);   Future<ResultB> f2 = executor.submit(task2);   // ... use futures}

上面的代码仍然使用ExecutorService,但从Executors.newVirtualThreadPerTaskExecutor()返回的代码没有使用线程池。相反,它为每个提交的任务创建一个新的虚拟线程。G9O28资讯网——每日最新资讯28at.com

此外,ExecutorService本身是轻量级的,我们可以像创建任何简单对象一样创建一个新的对象。这使得我们可以依赖新添加的ExecutorService#close方法和try-with-resources构造。close方法会在try块结束时隐式调用,它会自动等待所有提交给ExecutorService的任务(即由ExecutorService生成的所有虚拟线程)结束。G9O28资讯网——每日最新资讯28at.com

对于扇出场景来说,这是一个特别有用的模式,在这种场景中,同时执行多个对不同服务调用,如下面的示例所示:G9O28资讯网——每日最新资讯28at.com

void handle() throws Exception {  URL url1 = URI.create("http://www.pack.com").toURL() ;  URL url2 = URI.create("http://www.akf.com").toURL() ;  try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {    var future1 = executor.submit(() -> fetchURL(url1));    var future2 = executor.submit(() -> fetchURL(url2));    System.out.printf("result1: %s, result2: %s%n", future1.get(),future2.get()) ;  }}String fetchURL(URL url) throws IOException {  try (var in = url.openStream()) {    return new String(in.readAllBytes(), StandardCharsets.UTF_8);  }}

你应该创建一个新的虚拟线程,如上所示,即使是小的、短期的并发任务。G9O28资讯网——每日最新资讯28at.com

9. 避免长时间频繁的Pinning

当前实现虚拟线程的一个限制是,在同步的块或方法内部执行阻塞操作会导致JDK的虚拟线程调度器阻塞一个操作系统线程,而在同步的块或方法外部执行阻塞操作则不会。这种情况称为“Pinning”。如果阻塞操作持续时间长且频繁,Pinning可能会对服务器的吞吐量产生负面影响。保护短期的操作,例如内存操作,或者使用同步块或方法的不频繁操作,应该不会有任何负面影响。G9O28资讯网——每日最新资讯28at.com

对于长时间又频繁的地方应该使用ReentrantLock替换synchronized 。G9O28资讯网——每日最新资讯28at.com

synchronized(lockObj) {  frequentIO() ;}// 替换为lock.lock();try {  frequentIO() ;} finally {  lock.unlock() ;}


G9O28资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-92454-0.html提升系统吞吐量,详解JDK21虚拟线程,炸裂

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 强势问鼎!强力巨彩斩获 2023 年 LED 显示屏销量第一!

下一篇: 代码中预编译常见指令用法

标签:
  • 热门焦点
  • 6月安卓手机好评榜:魅族20 Pro蝉联冠军

    6月安卓手机好评榜:魅族20 Pro蝉联冠军

    性能榜和性价比榜之后,我们来看最后的安卓手机好评榜,数据来源安兔兔评测,收集时间2023年6月1日至6月30日,仅限国内市场。第一名:魅族20 Pro好评率:95%5月份的时候魅族20 Pro就是
  • 8月总票房已突破10亿!《封神》第一:口碑已经成了

    8月总票房已突破10亿!《封神》第一:口碑已经成了

    8月5日消息,据灯塔专业版数据,截至8月5日9时35分,8月总票房(含预售)已突破10亿。其中,《封神》以大比分的优势领先。根据官方消息,目前该片总票房已经超过14.
  • 十个可以手动编写的 JavaScript 数组 API

    十个可以手动编写的 JavaScript 数组 API

    JavaScript 中有很多API,使用得当,会很方便,省力不少。 你知道它的原理吗? 今天这篇文章,我们将对它们进行一次小总结。现在开始吧。1.forEach()forEach()用于遍历数组接收一参
  • 自动化在DevOps中的力量:简化软件开发和交付

    自动化在DevOps中的力量:简化软件开发和交付

    自动化在DevOps中扮演着重要角色,它提升了DevOps的效能。通过自动化工具和方法,DevOps团队可以实现以下目标:消除手动和重复性任务。简化流程。在整个软件开发生命周期中实现更
  • 花7万退货退款无门:谁在纵容淘宝珠宝商家造假?

    花7万退货退款无门:谁在纵容淘宝珠宝商家造假?

    来源:极点商业作者:杨铭在淘宝购买珠宝玉石后,因为保证金不够赔付,店铺关闭,退货退款难、维权无门的比比皆是。&ldquo;提供相关产品鉴定证书,支持全国复检,可以30天无理由退换货。&
  • ESG的面子与里子

    ESG的面子与里子

    来源 | 光子星球撰文 | 吴坤谚编辑 | 吴先之三伏大幕拉起,各地高温预警不绝,但处于厄尔尼诺大&ldquo;烤&rdquo;之下的除了众生,还有各大企业发布的ESG报告。ESG是&ldquo;环境保
  • 东方甄选单飞:有些鸟注定是关不住的

    东方甄选单飞:有些鸟注定是关不住的

    文/彭宽鸿编辑/罗卿东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一年多时间里,东方甄选要脱离抖音自立门户的传闻不绝于耳,&ldquo;7
  • 朋友圈可以修改可见范围了 苹果用户可率先体验

    朋友圈可以修改可见范围了 苹果用户可率先体验

    近日,iOS用户迎来微信8.0.27正式版更新,除了可更换二维码背景外,还新增了多项实用功能。在新版微信中,朋友圈终于可以修改可见范围,简单来说就是已发布的朋友圈
  • 中关村论坛11月25日开幕,15位诺奖级大咖将发表演讲

    中关村论坛11月25日开幕,15位诺奖级大咖将发表演讲

    11月18日,记者从2022中关村论坛新闻发布会上获悉,中关村论坛将于11月25至30日在京举行。本届中关村论坛由科学技术部、国家发展改革委、工业和信息化部、国务
Top
Baidu
map