0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是虚拟线程?虚拟线程到底是做什么用的呢?

OSC开源社区 来源:程序猿DD 2023-10-29 10:23 次阅读

什么是虚拟线程

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

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

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

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

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

bca3e94a-7565-11ee-939d-92fbcf53809c.png

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

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

平台线程需要将其调用堆栈存储在内存中

它是系统资源,启动平台线程大约需要一毫秒

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

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

bcb39016-7565-11ee-939d-92fbcf53809c.png

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

bcbcc924-7565-11ee-939d-92fbcf53809c.png

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

bcc12488-7565-11ee-939d-92fbcf53809c.png

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

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

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

虚拟线程可以运行任何Java代码或任何本机代码。

你不需要学习任何新概念。

但你需要忘掉某些想法,比如:

虚拟线程很便宜,比传统平台线程便宜大约 1,000 倍。

阻塞虚拟线程的成本也很低,因此试图避免阻塞虚拟线程是没有用的。

编写经典的阻塞代码是可以的,这是一个好消息,因为阻塞代码比异步代码更容易编写。此时,您可能想知道,池化虚拟线程是个好主意吗?嗯,答案是否定的。不要那样做。你只是在浪费时间。

关于虚拟线程还有两个好消息:线程局部变量也以同样的方式工作;同步也有效。关于同步有几件事需要说一下。虚拟线程仍然运行在平台线程之上,下面还有一个平台线程。不过,这个虚拟线程可以与其平台线程分离,以便这个平台线程可以运行另一个虚拟线程。什么时候才能脱离呢?虚拟线程一旦阻塞就可以与其平台线程分离。它可能会在I/O操作或同步操作上被阻止,或者可能会被置于睡眠状态。如果虚拟线程正在同步块内执行某些代码,则它无法与其平台线程分离。

因此,在运行此同步代码块期间,它会阻塞平台线程。如果这个时间很短,那也没关系。无需恐慌,也无需采取任何措施来防止这种情况发生。如果这个时间很长,也就是说,如果它正在做一些长时间的I/O操作,那么情况就不太好了。您可以通过简单地将对 synchronized 的调用替换为可重入锁来防止这种情况发生。

深入研究编码

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

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

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

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

bcce6c10-7565-11ee-939d-92fbcf53809c.png

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

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

bcd2911e-7565-11ee-939d-92fbcf53809c.png

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

它在幕后是如何工作的

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

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

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

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

bcd6dcb0-7565-11ee-939d-92fbcf53809c.png

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

bce4e12a-7565-11ee-939d-92fbcf53809c.pngbce925fa-7565-11ee-939d-92fbcf53809c.png

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

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

bcf4920a-7565-11ee-939d-92fbcf53809c.png

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

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

bd00b09e-7565-11ee-939d-92fbcf53809c.png

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

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

bd0801aa-7565-11ee-939d-92fbcf53809c.png

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

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

bd0c2ff0-7565-11ee-939d-92fbcf53809c.png

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

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

bd14389e-7565-11ee-939d-92fbcf53809c.png

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

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

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

bd17f038-7565-11ee-939d-92fbcf53809c.png

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

如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性专栏!

启动1000万个虚拟线程

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

bd1b8a9a-7565-11ee-939d-92fbcf53809c.png

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

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






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2904

    浏览量

    102994
  • SQL
    SQL
    +关注

    关注

    1

    文章

    738

    浏览量

    43461
  • 虚拟机
    +关注

    关注

    1

    文章

    855

    浏览量

    27375

原文标题:什么是虚拟线程?一次启1000万个会OOM吗?

文章出处:【微信号:OSC开源社区,微信公众号:OSC开源社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    MIPS架构上多线程的定义及用途

    在上一篇文章中,我对计算机虚拟化的基本概念及MIPS架构如何有效地实现硬件虚拟化进行了阐述。本文将主要探讨多线程,并尝试对其内涵及用途进行定义。 线程是一序列的指令。多
    发表于 02-09 14:44 1691次阅读

    Spring Boot虚拟线程和Webflux性能对比

    早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。
    发表于 09-24 14:54 294次阅读
    Spring Boot<b class='flag-5'>虚拟</b><b class='flag-5'>线程</b>和Webflux性能对比

    8205具体是做什么用?

    8205具体是做什么用?
    发表于 10-20 14:34

    ic618+spectre18+calibre2019虚拟到底是什么?

    ic618+spectre18+calibre2019虚拟到底是什么?有什么作用?
    发表于 06-22 08:00

    Linux系统的线程到底是什么

    在嵌入式操作系统中,任务相当于Linux系统的线程。在所有的操作系统中,线程(在嵌入式操作系统中一般称为任务)是一个单一顺序的执行流,是分配运行资源(CPU的运行时间)的基本单位。操作系统根据一定
    发表于 12-21 07:27

    线程好还是单线程好?单线程和多线程的区别 优缺点分析

    摘要:如今单线程与多线程已经得到普遍运用,那么到底线程好还是单线程好呢?单线程和多
    发表于 12-08 09:33 8w次阅读

    CPU与核心及进程和线程认识

    所谓的4核8线程,4核指的是物理核心。通过超线程技术,用一个物理核模拟两个虚拟核,每个核两个线程,总数为8线程
    的头像 发表于 03-30 14:48 7662次阅读
    CPU与核心及进程和<b class='flag-5'>线程</b>认识

    基于STM32的虚拟线程(TI_BLE协议栈_ZStack协议栈)

    基于STM32的虚拟线程,可以很好的用于裸机程序中,用于模拟小型操作系统的多线程概念。本实例参考了参考TI_BLE协议栈_ZStack协议栈。
    发表于 06-14 10:42 6659次阅读
    基于STM32的<b class='flag-5'>虚拟</b>多<b class='flag-5'>线程</b>(TI_BLE协议栈_ZStack协议栈)

    虚拟机:查看linux线程的CPU占用率的方法

    虚拟机:查看linux线程的CPU占用率的方法
    的头像 发表于 06-22 10:06 3860次阅读
    <b class='flag-5'>虚拟</b>机:查看linux<b class='flag-5'>线程</b>的CPU占用率的方法

    虚拟机:linux 进程的最大线程个数

    虚拟机:linux 进程的最大线程个数
    的头像 发表于 06-22 15:56 2457次阅读
    <b class='flag-5'>虚拟</b>机:linux 进程的最大<b class='flag-5'>线程</b>个数

    虚拟机:Linux查看线程信息的步骤

    虚拟机:Linux查看线程信息的步骤
    的头像 发表于 06-24 08:41 3266次阅读
    <b class='flag-5'>虚拟</b>机:Linux查看<b class='flag-5'>线程</b>信息的步骤

    探究到底什么是虚拟技术呢

    那么虚拟化技术到底是什么?其实广义上来说,就是通过映射或抽象的方式屏蔽物理设备复杂性。它可以有效简化基
    发表于 03-15 14:43 3494次阅读

    JDK 19 / Java 19正式发布 虚拟线程来了

    记录模式 (预览版) Linux/RISC-V 移植 外部函数和内存 API (预览版) 虚拟线程(预览版) Vector API (第四次孵化) Switch 模式匹配(第三预览版) 结构化并发(孵化阶段) JDK 19 / J
    的头像 发表于 10-10 17:08 1245次阅读

    4核8线程够用吗 核心和线程哪个重要

    这取决于您使用计算机的用途。如果您的用途包括日常办公、网页浏览、轻度视频处理等,则4核8线程足以满足需求。如果您需要进行高强度的图形处理、虚拟化、编程开发等,则可能需要更多的核心和线程
    的头像 发表于 06-01 17:50 1w次阅读

    Spring Boot 3.2支持虚拟线程和原生镜像

    Spring Boot 3.2 前几日发布,让我们用 Java 21、GraalVM 和虚拟线程来尝试一下。
    的头像 发表于 11-30 16:22 341次阅读