Project Loom:了解新的 Java 并发模型
mhr18 2024-12-27 16:20 16 浏览 0 评论
Loom 是 Java 和JVM生态系统中的一个较新的项目。Loom 项目由OpenJDK托管,解决了传统 Java 并发模型的局限性。特别是,它提供了一种更轻的线程替代方案,以及用于管理线程的新语言结构。虚拟线程已经是 Loom 最重要的部分,从 Java 21 开始成为 JDK 的一部分。
请继续阅读,了解 Loom 项目的概述以及它如何建议实现 Java 并发现代化。
Java中的虚拟线程
传统的 Java 并发性是通过Thread和Runnable类进行管理的,如清单 1 所示。
Thread thread = new Thread("My Thread") {
public void run(){
System.out.println("run by: " + getName());
}
};
thread.start();
System.out.println(thread.getName());
传统的 Java 并发性在简单的情况下相当容易理解,并且 Java为使用线程提供了丰富的支持。
fibers与虚拟线程
虚拟线程一度被命名为“fibers”,但为了避免与其他语言中的纤程混淆,该名称被放弃,取而代之的是“虚拟线程”。
缺点是 Java 线程直接映射到操作系统 (OS) 中的线程。这对并发 Java 应用程序的可伸缩性造成了严格的限制。它不仅意味着应用程序线程和操作系统线程之间存在一对一的关系,而且没有用于组织线程以实现最佳排列的机制。例如,密切相关的线程可能最终会共享不同的进程,而此时它们可以从共享同一进程上的堆中受益。
为了让您了解 Loom 中的变化有多么雄心勃勃,当前的 Java 线程,即使在大型服务器上,也以数千个线程计算(最多)。Loom 建议将此限制提高到数百万个线程。这对 Java 服务器可扩展性的影响是惊人的,因为标准请求处理与线程计数结合在一起。
解决方案是引入某种虚拟线程,其中 Java 线程从底层 OS 线程中抽象出来,JVM可以更有效地管理两者之间的关系。Loom 项目通过引入新的虚拟线程类来实现这一目标。由于新VirtualThread类具有与传统线程相同的 API 表面,因此很容易迁移。
延续和结构化并发
Continuations 是虚拟线程基础的低级功能。本质上,延续允许 JVM 停顿并重新启动执行流。
正如Project Loom 提案所述:
实现延续(实际上是整个项目)的主要技术任务是向 HotSpot 添加捕获、存储和恢复调用堆栈的能力,而不是作为内核线程的一部分。
Loom 的另一个功能是结构化并发,它为并发提供了线程语义的替代方案。结构化并发的主要思想是为您提供同步语法来处理异步流(类似于JavaScript 的 async 和 wait 关键字)。这对于 Java 开发人员来说是一个很大的福音,使简单的并发任务更容易表达。
如果您曾经接触过Quasar,它通过字节码操作为 Java 带来了轻量级线程,您可能还记得技术主管 Ron Pressler。Pressler 现在是 Oracle Loom 的负责人,他这样解释结构化并发:
结构化并发是一种范式,它将结构化编程的原理引入并发代码中,并使编写并发代码变得更容易,从而干净地处理并发编程中一些最棘手的长期问题:错误处理和取消。在 JDK 21 中,我们提供了StructuredTaskScope一个预览 API,为 JDK 带来了结构化编程。因为虚拟线程意味着程序中的每个并发任务都有自己的线程,虚拟线程和虚拟线程StructuredTaskScope是天作之合。除了使并发代码更容易正确编写之外,StructuredTaskScope还带来了结构化观察:捕获线程之间关系的线程转储。
虚拟线程的替代方案
在更仔细地研究 Loom 之前,我们先注意一下 Java 中针对并发性提出了多种方法。一般来说,这些相当于异步编程模型。有些(例如CompletableFutures非阻塞 IO)通过提高线程使用效率来解决边缘问题。其他的,比如RXJava(ReactiveX 的 Java 实现),是大规模的异步替代方案。
尽管 RXJava 是一种强大且具有潜在高性能的并发方法,但它也有缺点。特别是,它与 Java 开发人员传统上使用的概念模型有很大不同。而且,RXJava 无法与通过在虚拟机层管理虚拟线程实现的理论性能相匹配。
Java 的新 VirtualThread 类
如前所述,新VirtualThread类代表虚拟线程。在幕后,异步杂技正在进行中。为什么要这么麻烦,而不是在语言层面采用像 ReactiveX 这样的东西呢?答案是既让开发人员更容易理解,又让现有代码的迁移变得更容易。例如,数据存储驱动程序可以更轻松地过渡到新模型。
清单 2 显示了一个使用虚拟线程的简单示例。请注意,它与现有Thread代码非常相似。(这段代码片段来自Oracle对Loom和虚拟线程的介绍。)
清单 2. 创建虚拟线程
Thread.startVirtualThread(
() -> {
System.out.println("Hello World");
}
);
除了这个非常简单的示例之外,还有调度方面的广泛考虑因素。这些机制尚未确定,Loom 提案很好地概述了所涉及的想法。
关于 Loom 虚拟线程的一个重要注意事项是,无论整个 Java 系统需要做什么更改,都不能破坏现有代码。现有的线程代码将来将完全兼容。您可以使用虚拟线程,但不是必须的。实现这种向后兼容性是一项相当艰巨的任务,并且占用了 Loom 团队花费的大部分时间。
具有延续性的低级异步
现在我们已经了解了虚拟线程,让我们看一下仍在开发中的延续功能。Loom 支持虚拟线程和结构化并发的延续。还有人讨论将延续作为公共 API 供开发人员使用。那么,什么是延续呢?
从较高层次来看,延续是程序中执行流的代码表示。换句话说,延续允许开发人员通过调用函数来操纵执行流。Loom 文档提供了清单 3 中的示例,它提供了关于延续如何工作的良好心理图景。
清单 3. 延续的示例
foo() { // (2)
...
bar()
...
}
bar() {
...
suspend // (3)
... // (5)
}
main() {
c = continuation(foo) // (0)
c.continue() // (1)
c.continue() // (4)
}
考虑每个注释数字所描述的执行流程:
- foo(0) 从函数开始创建延续
- (1) 将控制权传递给 Continue 的入口点
- (2) 执行到下一个暂停点,即 (3)
- (3) 将控制释放回源头,位于 (1)
- (4) 现在执行,调用continue继续,流程返回到 (5) 处暂停的位置
尾调用消除
Loom 的另一个既定目标是尾部调用消除(也称为尾部调用优化)。这是所提议系统的一个相当深奥的元素。核心思想是系统将能够尽可能避免为延续分配新的堆栈。在这种情况下,执行延续所需的内存量保持一致,而不是不断构建,因为该过程中的每个步骤都需要保存先前的堆栈,并在调用堆栈展开时使其可用。
Loom 的下一步是什么
尽管 Loom 已经提供了很多值得探索的内容,但还有更多内容正在计划中。我向 Ron Pressler 询问了未来的路线图:
在短期内,我们正在努力解决可能是完全透明地采用虚拟线程的最大障碍:由于synchronized. 目前,在同步块或方法内,通常会释放底层操作系统线程的 IO 操作会阻塞它。这称为固定,如果这种情况发生得非常频繁且持续时间较长,则可能会损害虚拟线程的可扩展性优势。今天的解决方法是使用 JDK 中的观察工具识别这些实例,并用java.util.concurrent锁替换它们,这样就不会受到固定的影响。我们正在努力停止synchronized固定,以便不需要这项工作。此外,我们正在努力提高虚拟线程调度IO操作的效率,进一步提高其性能。
从中期来看,我们希望io_uring在可能的情况下合并,以提供除网络操作之外的文件系统操作的扩展。我们还希望提供自定义调度程序:虚拟线程当前由非常适合通用服务器的调度程序进行调度,但更奇特的用途可能需要其他调度算法,因此我们希望支持可插入的自定义调度程序。
进一步,我们希望添加通道(类似于阻塞队列,但具有附加操作,例如显式关闭),以及可能的生成器,就像在 Python 中一样,这使得编写迭代器变得容易。
Loom 和 Java 的未来
Loom 和 Java 通常主要致力于构建 Web 应用程序。显然,Java 还用于许多其他领域,Loom 引入的思想可能在各种应用程序中都有用。很容易看出,大幅提高线程效率并显着减少处理多个竞争需求的资源需求将如何提高服务器的吞吐量。更好地处理请求和响应对于整个现有和未来的 Java 应用程序来说是一个底线胜利。
与任何雄心勃勃的新项目一样,Loom 也并非没有挑战。处理复杂的线程交错(虚拟或其他线程)总是很复杂,我们必须等待才能确切地看到出现哪些库支持和设计模式来处理 Loom 的并发模型。
随着 Project Loom 进入 Java 的主要分支并根据现实世界的使用而不断发展,这将是一件令人着迷的事情。随着这一过程的展开,以及新系统固有的优势被应用到开发人员所依赖的基础设施中(想想像 Jetty 和Tomcat这样的 Java 应用服务器),我们可以见证 Java 生态系统发生翻天覆地的变化。
Java 和它的主要服务器端竞争对手Node.js在性能上已经不相上下。在典型的 Web 应用程序用例中,Java 性能的数量级提升可能会改变未来几年的格局。
相关推荐
- Java培训机构,你选对了吗?(java培训机构官网)
-
如今IT行业发展迅速,不仅是大学生,甚至有些在职的员工都想学习java开发,需求量的扩大,薪资必定增长,这也是更多人选择java开发的主要原因。不过对于没有基础的学员来说,java技术不是一两天就能...
- 产品经理MacBook软件清单-20个实用软件
-
三年前开始使用MacBookPro,从此再也不想用Windows电脑了,作为生产工具,MacBook可以说是非常胜任。作为产品经理,值得拥有一台MacBook。MacBook是工作平台,要发挥更大作...
- RAD Studio(Delphi) 本月隆重推出新的版本12.3
-
#在头条记录我的2025#自2024年9月,推出Delphi12.2版本后,本月隆重推出新的版本12.3,RADStudio12.3,包含了Delphi12.3和C++builder12.3最...
- 图解Java垃圾回收机制,写得非常好
-
什么是自动垃圾回收?自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制。所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象;而未使用中的对象(未引用...
- Centos7 初始化硬盘分区、挂载(针对2T以上)添加磁盘到卷
-
1、通过命令fdisk-l查看硬盘信息:#fdisk-l,发现硬盘为/dev/sdb大小4T。2、如果此硬盘以前有过分区,则先对磁盘格式化。命令:mkfs.文件系统格式-f/dev/sdb...
- 半虚拟化如何提高服务器性能(虚拟化 半虚拟化)
-
半虚拟化是一种重新编译客户机操作系统(OS)将其安装在虚拟机(VM)上的一种虚拟化类型,并在主机操作系统(OS)运行的管理程序上运行。与传统的完全虚拟化相比,半虚拟化可以减少开销,并提高系统性能。虚...
- HashMap底层实现原理以及线程安全实现
-
HashMap底层实现原理数据结构:HashMap的底层实现原理主要依赖于数组+链表+红黑树的结构。1、数组:HashMap最底层是一个数组,称为table,它存放着键值对。2、链...
- long和double类型操作的非原子性探究
-
前言“深入java虚拟机”中提到,int等不大于32位的基本类型的操作都是原子操作,但是某些jvm对long和double类型的操作并不是原子操作,这样就会造成错误数据的出现。其实这里的某些jvm是指...
- 数据库DELETE 语句,还保存原有的磁盘空间
-
MySQL和Oracle的DELETE语句与数据存储MySQL的DELETE操作当你在MySQL中执行DELETE语句时:逻辑删除:数据从表中标记为删除,不再可见于查询结果物理...
- 线程池—ThreadPoolExecutor详解(线程池实战)
-
一、ThreadPoolExecutor简介在juc-executors框架概述的章节中,我们已经简要介绍过ThreadPoolExecutor了,通过Executors工厂,用户可以创建自己需要的执...
- navicat如何使用orcale(详细步骤)
-
前言:看过我昨天文章的同鞋都知道最近接手另一个国企项目,数据库用的是orcale。实话实说,也有快三年没用过orcale数据库了。这期间问题不断,因为orcale日渐消沉,网上资料也是真真假假,难辨虚...
- 你的程序是不是慢吞吞?GraalVM来帮你飞起来性能提升秘籍大公开
-
各位IT圈内外的朋友们,大家好!我是你们的老朋友,头条上的IT技术博主。不知道你们有没有这样的经历:打开一个软件,半天没反应;点开一个网站,图片刷不出来;或者玩个游戏,卡顿得想砸电脑?是不是特别上火?...
- 大数据正当时,理解这几个术语很重要
-
目前,大数据的流行程度远超于我们的想象,无论是在云计算、物联网还是在人工智能领域都离不开大数据的支撑。那么大数据领域里有哪些基本概念或技术术语呢?今天我们就来聊聊那些避不开的大数据技术术语,梳理并...
- 秒懂列式数据库和行式数据库(列式数据库的特点)
-
行式数据库(Row-Based)数据按行存储,常见的行式数据库有Mysql,DB2,Oracle,Sql-server等;列数据库(Column-Based)数据存储方式按列存储,常见的列数据库有Hb...
- AMD发布ROCm 6.4更新:带来了多项底层改进,但仍不支持RDNA 4
-
AMD宣布,对ROCm软件栈进行了更新,推出了新的迭代版本ROCm6.4。这一新版本里,AMD带来了多项底层改进,包括更新改进了ROCm的用户空间库和AMDKFD内核驱动程序之间的兼容性,使其更容易...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (56)
- oracle 乐观锁 (53)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)