启动1000万个虚拟线程需要多少时间?需要多少平台线程?

之前,在Java新特性专栏中,我们简单介绍了Java 21正式发布的虚拟线程。

昨天,正好看到一个讲解此内容的视频,非常不错,所以DD这里给大家翻译好了,感兴趣的可以看看。可以进一步了解虚拟线程。

什么是虚拟线程?一次启1000万个会怎么样?

该视频采用Chrome插件Youtube中文配音做了翻译+配音处理,如果您平时也有上油管看前沿视频的话,也可以装一个,可以有效的提高你的学习效率 _

如果您当前环境不适合观看视频,也可以通过下面的文字内容学习。下面内容是我根据视频内容,总结的,会更简洁一些。

什么是虚拟线程

虚拟线程是在Java并发领域添加的一个新概念,那么虚拟线程到底是做什么用的呢?

根据JEP中的内容告诉我们,虚拟线程是一种轻量级线程,可以显著地帮助我们减少编写、维护、观察高吞吐量应用程序的工作量。它的实现目标有以下几点:

  1. 每个请求一个线程风格编写的程序,能够以接近最佳硬件利用率进行扩展。

什么是每个请求一个线程的风格?

对于HTTP服务器来说,这意味着每个HTTP请求都由它自己的线程处理。对于关系型数据库服务器来说,这意味着每个SQL事务也都由它自己的线程处理。如果您曾经使用过 Java EE 服务器,那么它就是这样工作的。所以,什么是每个请求一个线程的风格就是:一个请求 = 一个事务 = 一个线程

那么,这个模型的成本是多少呢? 要了解这个成本,您需要了解 Java 中线程的成本。平台线程和 CPU 使用率的成本。

Java 线程是在 Java 的早期版本中创建的,属于平台线程,也称为操作系统线程上的薄包装器。关于它们,您需要了解两件事。

  • 平台线程需要将其调用堆栈存储在内存中
  • 它是系统资源,启动平台线程大约需要一毫秒

事实上,平台线程是一种相当昂贵的资源。如何利用此类线程优化硬件利用率呢?

假设您的应用程序有 16 GB 的可用内存。除以 20 MB 的线程大小,这样的机器上就有 800 个线程的空间。假设这些线程正在执行一些 I/O,就像访问网络上的资源一样。假设该资源在 100 毫秒内被访问。准备请求和处理响应将在 10 纳秒的时间内完成。假设所有这些内存计算需要 1000 纳秒。这意味着在准备请求和处理响应之间存在一个大约 100000 的因素,以及获得响应所需的时间,在此期间您的线程就在那里什么都不做。所以如果你有 800 个这样的线程,那么CPU利用率只有可怜的0.8%。

如果你将内存加倍到 32 GB,那么CPU利用率可以达到1.3%,但这仍然很低。

反过来思考下,如果我们希望达到90%的CPU利用率。那么就需要 90000 个线程,启动它们需要 90秒,同时,还要消耗 1.8 TB 的内存。

很明显,平台线程的成本太高,无法以接近最佳的硬件利用率进行扩展。因此,我们需要另一种线程模型来解决这样的问题。

  1. 使基于经典 Java 线程的现有代码能够以最小更改代价来使用虚拟线程

这一目标意味着可以把经典线程做的所有事情,轻松的转换为虚拟线程的处理方式来完成。这里涵盖了几个关键点。

  • 虚拟线程可以运行任何Java代码或任何本机代码。
  • 你不需要学习任何新概念。
  • 但你需要忘掉某些想法,比如:
    • 虚拟线程很便宜,比传统平台线程便宜大约 1,000 倍。
    • 阻塞虚拟线程的成本也很低,因此试图避免阻塞虚拟线程是没有用的。
    • 编写经典的阻塞代码是可以的,这是一个好消息,因为阻塞代码比异步代码更容易编写。此时,您可能想知道,池化虚拟线程是个好主意吗?嗯,答案是否定的。不要那样做。你只是在浪费时间。

关于虚拟线程还有两个好消息:线程局部变量也以同样的方式工作;同步也有效。关于同步有几件事需要说一下。虚拟线程仍然运行在平台线程之上,下面还有一个平台线程。不过,这个虚拟线程可以与其平台线程分离,以便这个平台线程可以运行另一个虚拟线程。什么时候才能脱离呢?虚拟线程一旦阻塞就可以与其平台线程分离。它可能会在I/O操作或同步操作上被阻止,或者可能会被置于睡眠状态。如果虚拟线程正在同步块内执行某些代码,则它无法与其平台线程分离。因此,在运行此同步代码块期间,它会阻塞平台线程。如果这个时间很短,那也没关系。无需恐慌,也无需采取任何措施来防止这种情况发生。如果这个时间很长,也就是说,如果它正在做一些长时间的I/O操作,那么情况就不太好了。您可以通过简单地将对 synchronized 的调用替换为可重入锁来防止这种情况发生。

深入研究编码

关于如何创建虚拟线程,在之前的Java 21新特性虚拟线程中有提到。通过Thread.ofVirtual()即可,比如:

Thread.ofVirtual()
        .name("didispace-virtual-thread")
        .start(runnable);

Tips:如果要创建平台线程,则可使用:Thread.ofPlatform()

虚拟线程工作在平台线程之上。您可能认为没有任何性能提升,只是产生了开销。那么到底是怎么回事呢?关于虚拟线程还有更多内容。下面一起来看看这段代码是如何运行的。

这段代码中,使用了流模式创建 10 个虚拟的、未启动的线程。这些线程正在运行的任务只是打印当前线程。然后,让它们休眠 10 毫秒,接着再次打印线程的名称。最后,启动这些未启动的线程并调用 join 方法以确保所有内容都可以在控制台上看到。

那么运行这段代码,您会发现这里发生了一些真正意想不到的事情。

这个ForkJoinPool的线程7,当它从睡眠状态回来时,它并没有继续运行在原来的平台线程上,而是跳转到了另外一个平台线程。如果您在自己的计算机上执行此操作,请确保启动足够的虚拟线程,因为您可能不会仅使用一两个线程来观察到这一点。

它在幕后是如何工作的

事实上,当虚拟线程由于某些操作而被阻塞时,相应的堆栈就会从其运行的平台线程移动到堆内存中。所以,现在这个平台线程可以自由地运行另一个虚拟线程。当这个任务收到可以继续运行的信号时,它的堆栈就会从堆移回平台线程,但不一定相同。所以,这就是阻塞虚拟线程的代价,将该虚拟线程的堆栈移动到主内存并返回。阻塞虚拟线程并不是免费无开销的,但它比阻塞平台线程要划算得多。

Tips: 这段逻辑视频里有图形化的解释,推荐结合视频动画观看,会更容易理解。

令人高兴的是,JDK 的所有阻塞操作都已被重构以利用它。其中包括I/O操作、同步和Thread.sleep

需要多少平台线程来运行虚拟线程

关于这个问题,我们可以测试一下。让我创建虚拟线程并收集所有相应的平台线程名称。

该代码基本上启动了五个虚拟线程,然后使用一些代码提取池名称和平台线程名称。最后,它只是打印不同的统计信息、运行此代码所需的时间、CPU 上的核心数量、线程池数量,以及平台线程的数量。

那么让我运行这段代码,可以看到如下结果:

对于 5 个虚拟线程,它使用 3 个平台线程并花费 2 毫秒。

让我使用 10 个虚拟线程并再次运行代码。

对于 10 个线程,它仍然使用 3 个平台线程并花费了 4 毫秒。

让我使用 100 个虚拟线程并再次运行代码。

现在它使用 7 个平台线程。

让我们看看 1,000 个虚拟线程会发生什么。

它仍然使用 7 个平台线程。

试试10万个虚拟线程怎么样?

现在它使用 8 个平台线程,花费了 156 毫秒。

顺便说一句,即使这些线程没有做太多事情,只是一些字符串操作和在并发集中添加元素,您也可以看到运行所有这些线程只需要 156 毫秒。

现在让我增加到 100 万个线程。

花费了不到一秒的时间,并且仍然使用 8 个平台线程。

启动1000万个虚拟线程

我们尝试启动 1000 万个虚拟线程怎么样?你曾经尝试过这样做吗?在您的机器上启动 1000 万个平台线程?嗯,通常这是不可能的,但是使用虚拟线程,我们也许能够做到。我们可以获得如下结果:

这还只是在一台旧笔记本电脑上测试的结果,只需要不到 7 秒的时间,这真是太棒了!

这就是Java 中的虚拟线程!是不是很棒?那么,你是否已经开始升级Java 21并开始使用此特性来提升你的应用性能了呢?留言区一起聊聊吧。

码字不易,如果您喜欢本文,欢迎点赞、在看、转发支持一下。如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性专栏!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/104339.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是Docker CLI

Docker CLI(命令行界面)是一个工具,允许用户通过命令行或终端与Docker进行交互。Docker是一个开源平台,用于开发、运送和运行应用程序。Docker使用容器化技术来打包应用程序及其依赖项,以确保在不同环境中的一致性和隔…

配置Sentinel 控制台

1.遇到的问题 服务网关 | RuoYi 最近调试若依的微服务版本需要用到Sentinel这个组件,若依内部继承了这个组件连上即用。 Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面。 在日常开发中,限流功能时常被使用,用…

Python UI自动化 —— pytest常用运行参数解析、pytest执行顺序解析

pytest常用Console参数: -v 用于显示每个测试函数的执行结果-q 只显示整体测试结果-s 用于显示测试函数中print()函数输出-x 在第一个错误或失败的测试中立即退出-m 只运行带有装饰器配置的测试用例-k 通过表达式运行指定的测试用例-h 帮助 首先来看什么参数都没加…

微信小程序实现文章内容详情

方案一、使用微信小程序官方提供的webview 前提已经在微信公众平台开发管理配置好了安全域名即: 方案二、把网页转成pdf直接展示 前提已经在微信公众平台开发管理配置好了安全域名即: 实现思路是发起网络请求拿到pdf下载地址,然后wx.download…

深度学习模型笔记

加载和保存模型参数 保存模型参数 net MLP() # 此处省略训练过程,在训练之后,保存模型参数 # 保存字典格式的模型参数,模型参数名 torch.save(net.state_dict(), mlp.params) 加载模型参数 clone MLP() # 加载模型参数 clone.load_state…

【C++】Map和Set -- 详解

一、关联式容器 在初阶阶段,我们已经接触过 STL 中的部分容器,比如:vector、list、deque、forward_list(C11)等,这些容器统称为 序列式容器 ,因为其底层为线性序列的数据结构,里面存…

计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)

车辆跟踪及测距 该项目一个基于深度学习和目标跟踪算法的项目,主要用于实现视频中的目标检测和跟踪。该项目使用了 YOLOv5目标检测算法和 DeepSORT 目标跟踪算法,以及一些辅助工具和库,可以帮助用户快速地在本地或者云端上实现视频目标检测和…

双向电平电压转换器TXS0102DCTR应用电路设计

1、TXS0102简介 TXS0102DCTR是一个2位双向电压电平转换器,主要用途是与数据I/O(例如I2C或1-wire)上的开漏驱动器连接(其中数据是双向的且无可用的控制信号),在混合电压系统之间建立数字开关兼容性。它使用…

保存 uboot图像配置

一. 简介 本文学习如何保存经过图像配置,与加载 自己的配置文件。 之前几篇文章学习了:uboot 经过图形化配置 dns 命令功能。地址如下: uboot通过图像化界面配置 dns命令-CSDN博客 uboot通过图像化界面配置 dns命令验证-CSDN博客 二. 保…

【C++基础入门】42.C++中同名覆盖引发的问题

一、父子间的赋值兼容 子类对象可以当作父类对象使用&#xff08;兼容性) 子类对象可以直接赋值给父类对象子类对象可以直接赋值给父类对象父类指针可以直接指向子类对象父类引用可以直接引用子类对象 下面看一个子类对象兼容性的代码&#xff1a; #include <iostream>…

大模型在数据分析场景下的能力评测

“你们能对接国产大模型吗&#xff1f;” “开源的 LLaMA 能用吗&#xff0c;中文支持怎么样&#xff1f;” “私有化部署和在线服务哪个更合适&#xff1f;” 自 7 月 14 日发布 AI 数智助理 Kyligence Copilot 后&#xff0c;我们收到了很多类似上面的咨询&#xff0c;尤其…

如何处理单据保存/审核时提示:“更新即时库存时,基本单位数量与辅单位数量为一正一负,即时库存更新不成功

文章目录 如何处理单据保存/审核时提示:“更新即时库存时,基本单位数量与辅单位数量为一正一负,即时库存更新不成功问题描述前提问题分析&#xff1a;解决方案 如何处理单据保存/审核时提示:“更新即时库存时,基本单位数量与辅单位数量为一正一负,即时库存更新不成功 问题描述…

使用C# RDLC环境搭建

搭建C# RDLC环境 在vs环境中&#xff0c;菜单扩展>管理扩展 用来打开报表文件的 用来新建报表文件的 搜索Microsoft Reporting Services Projects 选择第一个进行下载 安装完以上两个即可进行报表文件的创建和预览 reportview组件 推荐nuget安装&#xff1a;Install-…

前后端交互—跨域与HTTP

跨域 代码下载 同源策略 同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。 MDN 官方给定的概念:同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这 是一个用于隔离潜在恶意文件的重要安全机制。 通俗的理解:浏览器规定&a…

拆贡献+统计非法可能不统计非法贡献:ARC150D

https://atcoder.jp/contests/arc150/tasks/arc150_d 先拆贡献成每个点&#xff0c;然后就只需要考虑这条链上的情况了 我们现在要求的是&#xff1a; 在所有点选完之前&#xff0c;最后一个点被选了多少次 我们发现这很难做&#xff0c;但有个性质&#xff1a; 在所有点选…

CLion使用SSH远程连接Linux服务器

最近要一直用实验室的服务器写Linux下的C代码, 本来一直用VScode(SSH)连接服务器, 但是我以前还是用JetBrains的IDE用的多, 毕竟他家的IDE代码提示和功能在某些细节上更加丰富。所以这次我使用了Clion里的远程连接(同样也是SSH工具)连接上了我的服务器, 实现了和VScode上同样的…

计算机网络-计算机网络体系结构-应用层

目录 一、网络应用模型 客户/服务器模型(Client/Server) P2P模型(Peer-to-peer) 二、域名解析系统(DNS) 域名 域名服务器 解析过程 三、文件传输协议(FTP) FTP控制原理 四、电子邮件 组成结构 协议 SMTP MIME POP3 IMAP 五、万维网和HTTP协议 概述 HTTP 报…

Python---for循环中的两大关键字break和continue

之前在while循环中&#xff0c;也是用到两个关键字。 相关链接&#xff1a; 所以&#xff0c;在循环结构中都存在两个关键字&#xff1a;break和continue break&#xff1a;主要功能是终止整个循环 break&#xff1a;代表终止整个循环结构 continue&#xff1a;代表中止当…

selenium元素定位之xpath

一、找父级节点parent xpath&#xff1a;//span[text()保存]/parent::button 说明&#xff1a;先找到span标签&#xff0c;再找到父级button 一、找同级的上方标签preceding-sibling xpath&#xff1a;//span[text()保存]/parent::button/preceding-sibling::button[1] 说明…

基于Java的足球赛会管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…