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

news2024/12/26 0:33:29

之前,在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新特性专栏!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二进制搭建 Kubernetes+部署网络组件+部署CornDNS+负载均衡部署+部署Dashboard

二进制搭建 Kubernetes v1.20 k8s集群master01:20.0.0.50 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02:20.0.0.100k8s集群node01:20.0.0.110 kubelet kube-proxy docker etcd k8s集群node02:20.…

ArcGIS笔记12_ArcGIS搜索工具没法用?ArcGIS运行很慢很卡?

本文目录 前言Step 1 ArcGIS搜索工具没法用Step 2 ArcGIS运行很慢很卡 前言 这是笔者最近遇到的两个小问题,新换了台式机,安装上ArcGIS后发现搜索工具没法用,而且感觉还不如原来笔记本运行的流畅,加载图层很慢,编辑要…

基于YOLOv8模型和UA-DETRAC数据集的车辆目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要:基于YOLOv8模型和UA-DETRAC数据集的车辆目标检测系统可用于日常生活中检测与定位汽车(car)、公共汽车(bus)、面包车(vans)等目标,利用深度学习算法可实现图片、视频、摄像头等方…

μCOS-Ⅲ中断管理,这样理解非常简单!

μCOS-Ⅲ中断管理,这样理解非常简单! 文章目录 μCOS-Ⅲ中断管理,这样理解非常简单!前言一、中断源与中断优先级二、μCOS-Ⅲ的中断管理方式三、中断屏蔽与中断控制1、μCOS-Ⅲ中断开关2、μCOS-Ⅲ中断屏蔽应用——临界区4、μCOS…

sqoop和flume简单安装配置使用

1. Sqoop 1.1 Sqoop介绍 Sqoop 是一个在结构化数据和 Hadoop 之间进行批量数据迁移的工具 结构化数据可以是MySQL、Oracle等关系型数据库 把关系型数据库的数据导入到 Hadoop 与其相关的系统 把数据从 Hadoop 系统里抽取并导出到关系型数据库里 底层用 MapReduce 实现数据 …

Linux区分文件类型,file指令,目录权限,umask掩码,共享文件,Linux中的一些有趣指令

file指令,Linux区分文件类型,目录权限,umask掩码,共享文件,Linux中的一些有趣指令 1.Linux中是如何区分文件类型的2. file指令3.目录权限4.umask掩码5.粘滞位6.Linux中的一些有趣指令 所属专栏:Linux学习❤…

计算机网络-TCP协议

面向连接的运输:TCP TCP连接 TCP被称为面向连接的,因为在应用程序开始互传数据之前,TCP会先建立一个连接,该连接的建立涉及到三次“握手”。 TCP的连接不是一条真实存在的电路,而是一条逻辑链接,其共同状…

EL表达式和JSTL标签库

2023.10.25 EL表达式是什么&#xff1f; EL表达式&#xff0c;Expression Language&#xff08;表达式语言&#xff09;&#xff0c;可以代替JSP中的java代码&#xff0c;让JSP文件中的程序看起来更加整洁&#xff0c;美观。 由于JSP中夹杂着各种java代码&#xff0c;例如<…

MySQL---表的增查改删(CRUD进阶)

文章目录 数据库约束表的设计一对一一对多多对多 新增查询聚合查询分组查询联合查询内连接外连接自连接子查询合并查询 数据库约束 数据库约束就是指&#xff1a;程序员定义一些规则对数据库中的数据进行限制。这样数据库会在新增和修改数据的时候按照这些限制&#xff0c;对数…

[ACTF2020 新生赛]Exec

【解题过程】 1.打开链接 得到一个能ping 的网站&#xff0c;可以推测这个可以在终端运行的网站。 2.解题思路 在执行的时候我们可以想到命令执行的“&#xff1b;”分号的作用&#xff1a;命令用分号分隔开来&#xff0c;表示它们是两个独立的命令&#xff0c;需要依次执行。…

【Docker】Docker的网络

Docker提供了多种内置的网络模式&#xff0c;用于在容器之间建立网络连接。这些网络模式&#xff0c;包括桥接网络、主机网络、无网络模式。我们将主要探讨每种网络模式的优缺点、适用场景。 桥接网络 桥接网络是Docker的默认网络模式。在桥接网络中&#xff0c;Docker会为每…

Pytorch代码入门学习之分类任务(一):搭建网络框架

目录 一、网络框架介绍 二、导包 三、定义卷积神经网络 3.1 代码展示 3.2 定义网络的目的 3.3 Pytorch搭建网络 四、测试网络效果 一、网络框架介绍 网络理解&#xff1a; 将32*32大小的灰度图片&#xff08;下述的代码中输入为32*32大小的RGB彩色图片&#xff09;&…

论多段图的最短路径问题(我认为本质上还是暴力枚举法)

比如说这道题&#xff1a;我向前推进 从0到11的最短路径 按照图可以分5段&#xff0c;v1 是第一阶段 0&#xff0c;v2是第二段 有1&#xff0c;2&#xff0c;3&#xff0c;4 从0开始&#xff0c;路径为0&#xff0c;所以m&#xff08;1&#xff0c;0&#xff09;0&#xff1b…

单片机核心/RTOS必备 (ARM汇编)

ARM汇编概述 一开始&#xff0c;ARM公司发布两类指令集&#xff1a; ARM指令集&#xff0c;这是32位的&#xff0c;每条指令占据32位&#xff0c;高效&#xff0c;但是太占空间。Thumb指令集&#xff0c;这是16位的&#xff0c;每条指令占据16位&#xff0c;节省空间。 要节…

reqable(小黄鸟)+雷电抓包安卓APP

x 下载证书保存到雷电模拟器根目录(安装位置) 在根目录打开cmd执行命令 F:\Program\leidian\LDPlayer9>adb push reqable-ca.crt /system/etc/security/cacerts/364618e0.0 reqable-ca.crt: 1 file pushed, 0 skipped. 0.8 MB/s (1773 bytes in 0.002s)如果是powershell…

Hadoop3.0大数据处理学习4(案例:数据清洗、数据指标统计、任务脚本封装、Sqoop导出Mysql)

案例需求分析 直播公司每日都会产生海量的直播数据&#xff0c;为了更好地服务主播与用户&#xff0c;提高直播质量与用户粘性&#xff0c;往往会对大量的数据进行分析与统计&#xff0c;从中挖掘商业价值&#xff0c;我们将通过一个实战案例&#xff0c;来使用Hadoop技术来实…

Node编写更新用户头像接口

目录 定义路由和处理函数 验证表单数据 ​编辑 实现更新用户头像的功能 定义路由和处理函数 向外共享定义的更新用户头像处理函数 // 更新用户头像的处理函数 exports.updateAvatar (req, res) > {res.send(更新成功) } 定义更新用户头像路由 // 更新用户头像的路由…

Liunx-Kubernetes安装

安装Kubernetes Kubernetes有多种部署方式&#xff0c;目前主流的方式有kubeadm、minikube、二进制包 minikube&#xff1a;一个用于快速搭建单节点kubernetes的工具kubeadm&#xff1a;一个用于快速搭建kubernetes集群的工具二进制包&#xff1a;从官网下载每个组件的二进制…

浏览器多开,数据之间相互不干扰

方法很简单 在浏览器快捷方式中&#xff0c;快捷键点开属性&#xff0c;在目标中添加--user-data-dirD:\chrome\1