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

Java 21 的虚拟线程:高性能并发应用的福音

来源: 责编: 时间:2023-12-08 09:14:12 331观看
导读Java 21 最重要的特性之一就是虚拟线程 (JEP 444)。这些轻量级的线程降低了编写、维护和观察高吞吐量并行应用所需的努力。在讨论新特性之前,让我们先看一下当前的状态,以便更好地理解它试图解决什么问题以及带来了哪些

Java 21 最重要的特性之一就是虚拟线程 (JEP 444)。这些轻量级的线程降低了编写、维护和观察高吞吐量并行应用所需的努力。x6I28资讯网——每日最新资讯28at.com

在讨论新特性之前,让我们先看一下当前的状态,以便更好地理解它试图解决什么问题以及带来了哪些好处。x6I28资讯网——每日最新资讯28at.com

平台线程

在引入虚拟线程之前,我们习惯使用的线程是 java.lang.Thread,它背后是所谓的平台线程 (platform threads)。x6I28资讯网——每日最新资讯28at.com

这些线程通常与操作系统调度的内核线程一一映射。操作系统线程相当“重”,这使得它们适合执行所有类型的任务。x6I28资讯网——每日最新资讯28at.com

根据操作系统和配置,它们默认情况下会消耗大约2到10 MB的内存。因此,如果你想在高负载并发应用程序中使用一百万个线程,最好要有超过2 TB的可用内存!x6I28资讯网——每日最新资讯28at.com

这存在一个明显的瓶颈,限制了我们实际可以在没有缺点的情况下拥有的线程数量。x6I28资讯网——每日最新资讯28at.com

每个请求一个线程

这很成问题,因为它直接与典型的服务器应用程序“每个请求一个线程”的方法相冲突。使用每个请求一个线程有很多优点,例如更简单的状态管理和清理。但它也创造了可扩展性限制。应用程序的“并发单位”,在这种情况下是一个请求,需要一个“平台并发单位”。因此,线程很容易被原始CPU能力或网络耗尽。x6I28资讯网——每日最新资讯28at.com

即使“每个请求一个线程”有许多优点,共享重量级的线程可以更均匀地利用硬件,但也需要一种完全不同的方法。x6I28资讯网——每日最新资讯28at.com

异步救援

而不是在单个线程上运行整个请求,它的每个部分都从池中使用一个线程,当它们的任务完成时,另一个任务可能会重用同一个线程。这允许代码需要更少的线程,但引入了异步编程的负担。x6I28资讯网——每日最新资讯28at.com

异步编程伴随着它自己的范例,具有一定的学习曲线,并且可能会使程序更难理解和跟踪。请求的每个部分可能都在不同的线程上执行,从而创建没有合理上下文的堆栈跟踪,并使调试某些内容变得非常棘手甚至几乎不可能。x6I28资讯网——每日最新资讯28at.com

Java有一个用于异步编程的优秀API,CompletableFuture。但这是一个复杂的API,并且不太适合许多Java开发人员习惯的思维方式。x6I28资讯网——每日最新资讯28at.com

重新审视“每个请求一个线程”模型,很明显,一种更轻量级的线程方法可以解决瓶颈并提供一种熟悉的做事方式。x6I28资讯网——每日最新资讯28at.com

轻量级线程

由于平台线程的数量是无法在没有更多硬件的情况下改变的,因此需要另一个抽象层,切断可怕的 1:1 映射,它是首先造成瓶颈的原因。x6I28资讯网——每日最新资讯28at.com

轻量级线程不与特定的平台线程绑定,也不会伴随大量的预分配内存。它们由运行时而不是底层操作系统调度和管理。这就是为什么可以创建大量轻量级线程的原因。x6I28资讯网——每日最新资讯28at.com

这个概念并不新鲜,许多语言都采用某种形式的轻量级线程:x6I28资讯网——每日最新资讯28at.com

  • Go 语言中的 Goroutine
  • Erlang 进程
  • Haskell 线程
  • 等等

Java最终于第21版中引入了自己的轻量级线程实现:虚拟线程 (Virtual Threads)。x6I28资讯网——每日最新资讯28at.com

虚拟线程

虚拟线程是一种新的轻量级java.lang.Thread变体,是Project Loom的一部分,它不是由操作系统管理或调度的。相反,JVM负责调度。x6I28资讯网——每日最新资讯28at.com

当然,任何实际的工作都必须在平台线程中运行,但是JVM使用所谓的“载体线程”(carrier threads) 来“携带”任何虚拟线程,以便在它们需要执行时执行这些线程。x6I28资讯网——每日最新资讯28at.com

图片图片x6I28资讯网——每日最新资讯28at.com

JVM/操作系统线程调度器x6I28资讯网——每日最新资讯28at.com

所需的平台线程在一个 FIFO 工作窃取 ForkJoinPool 中进行管理,该池默认情况下使用所有可用的处理器,但可以通过调整系统属性jdk.virtualThreadScheduler.parallelism来根据需求进行修改。x6I28资讯网——每日最新资讯28at.com

ForkJoinPool与其他功能(例如并行流)使用的通用池之间的主要区别在于,通用池以LIFO模式运行。x6I28资讯网——每日最新资讯28at.com

廉价且丰富的线程

拥有廉价且轻量级的线程,可以使用“每个请求一个线程”模型,而不必担心实际需要多少个线程。如果你的代码在虚拟线程中调用阻塞 I/O 操作,则运行时会挂起虚拟线程,直到它可以稍后恢复。x6I28资讯网——每日最新资讯28at.com

这样,硬件就可以被优化到几乎最佳的水平,从而实现高水平的并发性,因此也实现高吞吐量。x6I28资讯网——每日最新资讯28at.com

因为它们非常廉价,所以虚拟线程不会被重用或需要池化。每个任务都由其自己的虚拟线程表示。x6I28资讯网——每日最新资讯28at.com

设置边界

调度器负责管理载体线程,因此需要一定的边界和分离,以确保可能的“无数”虚拟线程按照预期运行。这是通过在载体线程及其可能携带的任何虚拟线程之间不保持线程关联来实现的:x6I28资讯网——每日最新资讯28at.com

  • 虚拟线程无法访问载体,Thread.currentThread() 返回虚拟线程本身。
  • 堆栈跟踪是分开的,任何在虚拟线程中抛出的异常只包含其自己的堆栈帧。
  • 虚拟线程的线程局部变量对它的载体不可用,反之亦然。
  • 从代码的角度来看,载体及其虚拟线程共享一个平台线程是不可见的。

让我们看看代码

使用Virtual Threads最大的好处是,你不需要学习新的范例或复杂的API,就像使用异步编程一样。相反,你可以像对待非虚拟线程一样处理它们。x6I28资讯网——每日最新资讯28at.com

创建平台线程

创建平台线程很简单,就像使用 Runnable 创建一样:x6I28资讯网——每日最新资讯28at.com

Runnable fn = () -> {    // your code here};Thread thread = new Thread(fn).start();

随着Project Loom简化了新的并发方法,它还提供了一种创建平台支持线程的新方法:x6I28资讯网——每日最新资讯28at.com

Thread thread = Thread.ofPlatform().                      .start(runnable);

实际上,现在还有一个完整的fluent API,因为ofPlatform()会返回一个Thread.Builder.OfPlatform实例:x6I28资讯网——每日最新资讯28at.com

Thread thread = Thread.ofPlatform().                      .daemon()                      .name("my-custom-thread")                      .unstarted(runnable);

但你肯定不是来学习创建“旧”线程的新方法的,我们想要一点新的东西。继续看。x6I28资讯网——每日最新资讯28at.com

创建虚拟线程

对于虚拟线程,也有类似的fluent API:x6I28资讯网——每日最新资讯28at.com

Runnable fn = () -> {  // your code here};Thread thread = Thread.ofVirtual(fn)                      .start();

除了构建器方法之外,你还可以直接使用以下方式执行Runnable:x6I28资讯网——每日最新资讯28at.com

Thread thread = Thread.startVirtualThread(() -> {  // your code here});

由于所有虚拟线程始终是守护线程,因此如果你想在主线程上等待,请不要忘记调用join()。x6I28资讯网——每日最新资讯28at.com

创建虚拟线程的另一种方法是使用 Executor:x6I28资讯网——每日最新资讯28at.com

var executorService = Executors.newVirtualThreadPerTaskExecutor();executorService.submit(() -> {  // your code here});

小结

尽管Scoped Values (JEP 446) 和Structured Concurrency (JEP 453) 仍然是Java 21中的预览功能,但Virtual Threads已经成为一个成熟的、适用于生产环境的功能。x6I28资讯网——每日最新资讯28at.com

它们是Java并发的一种通用且强大的新方法,将对我们未来的程序产生重大影响。它们使用了熟悉的和可靠的“每个请求一个线程”方法,同时以最优化的方式利用所有可用硬件,而不需要学习新的范例或复杂的API。x6I28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-39505-0.htmlJava 21 的虚拟线程:高性能并发应用的福音

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

上一篇: 你 UTF-8 乱码,关我 Unicode 什么事

下一篇: 一款小而美的开源滑动验证码组件

标签:
  • 热门焦点
  • Flowable工作流引擎的科普与实践

    一.引言当我们在日常工作和业务中需要进行各种审批流程时,可能会面临一系列技术和业务上的挑战。手动处理这些审批流程可能会导致开发成本的增加以及业务复杂度的上升。在这
  • 多线程开发带来的问题与解决方法

    使用多线程主要会带来以下几个问题:(一)线程安全问题  线程安全问题指的是在某一线程从开始访问到结束访问某一数据期间,该数据被其他的线程所修改,那么对于当前线程而言,该线程
  • 在线图片编辑器,支持PSD解析、AI抠图等

    自从我上次分享一个人开发仿造稿定设计的图片编辑器到现在,不知不觉已过去一年时间了,期间我经历了裁员失业、面试找工作碰壁,寒冬下一直没有很好地履行计划.....这些就放在日
  • 使用LLM插件从命令行访问Llama 2

    最近的一个大新闻是Meta AI推出了新的开源授权的大型语言模型Llama 2。这是一项非常重要的进展:Llama 2可免费用于研究和商业用途。(几小时前,swyy发现它已从LLaMA 2更名为Lla
  • JVM优化:实战OutOfMemoryError异常

    一、Java堆溢出堆内存中主要存放对象、数组等,只要不断地创建这些对象,并且保证 GC Roots 到对象之间有可达路径来避免垃 圾收集回收机制清除这些对象,当这些对象所占空间超过
  • 大厂卷向扁平化

    来源:新熵作者丨南枝 编辑丨月见大厂职级不香了。俗话说,兵无常势,水无常形,互联网企业调整职级体系并不稀奇。7月13日,淘宝天猫集团启动了近年来最大的人力制度改革,目前已形成一
  • 郭明錤称华为和江淮汽车合作开发问界MPV,定价100万左右、计划明年量产

    8 月 1 日消息,郭明錤今天在 Medium 平台发布博文,称华为正在和江淮汽车合作,开发售价在 100 万元的问界 MPV,预计在 2024 年第 2 季度量产,销量目标为
  • 机构称Q2国内智能手机销量同比下滑4% vivo份额重回第1

    7月29日消息,根据市场调查机构Counterpoint Research公布的最新报告,2023年第2季度中国智能手机销量同比下降4%,创新自2014年以来第2季度销量新低。报
  • 2纳米决战2025

    集微网报道 从三强争霸到四雄逐鹿,2nm的厮杀声已然隐约传来。无论是老牌劲旅台积电、三星,还是誓言重回先进制程领先地位的英特尔,甚至初成立不久的新
Top