超越传统线程:探索Java Loom协程(纤程/虚拟线程)的无限潜力

news2024/11/24 10:38:59

《超越传统线程:探索Java Loom协程(纤程/虚拟线程)的无限潜力》

一、Java协程的发展历程

Java协程的发展历程可以概括为以下几个阶段:

  • 1963年,协程的概念被正式提出,它的诞生甚至早于线程。
  • 2007年,Kilim项目发布,它是一个基于字节码增强技术的Java协程框架。
  • 2014年,Quasar项目发布,它是一个基于Agent技术的Java协程框架。
  • 2016年,Project Loom项目启动,它是一个旨在为Java提供原生协程支持的项目。
  • 2019年,Kotlin语言发布1.3版本,它是一个支持协程编程的Java兼容语言。
  • 2020年,Java 15发布,它包含了Project Loom的预览版(Preview Feature),提供了虚拟线程(Virtual Thread)和Scope Variable等特性。
  1. 早期尝试: 在 Java 早期版本中,并发主要通过线程和同步机制来实现。尽管 Java 提供了多线程支持,但由于线程的创建和切换开销较大,这使得高并发的场景处理效率较低。
  2. Quasar(2011年): Quasar 是由 Parallel Universe 开发的一个基于字节码操纵和 bytecode instrumentation 的 Java 协程库。它在 Java 中实现了类似协程的概念,通过操纵字节码来实现轻量级的协程和任务切换。Quasar 提供了协程式的编程方式,允许在一个线程中执行多个协程,从而避免了线程切换的开销。
  3. Kotlin Coroutines(2017年): Kotlin 是一种运行在 JVM 上的编程语言,由 JetBrains 开发。Kotlin Coroutines 是 Kotlin 的异步编程框架,允许以协程的方式编写异步代码。虽然 Kotlin 是一种独立的编程语言,但它可以与 Java 无缝集成,因此你可以在 Java 项目中使用 Kotlin Coroutines。
  4. Project Loom(进行中): Project Loom 是 OpenJDK 的一个子项目,致力于为 Java 引入轻量级线程(称为 Virtual Threads 或者 Loom Threads)。Loom 的目标是在不改变现有 Java 程序的前提下,为 Java 增加纤程的能力。Loom 的设计目标是实现一个高效且易用的协程和轻量级线程模型,以解决 Java 并发编程的挑战。

Java 标准库中仍然没有原生支持协程的特性。然而,上述项目和库的出现表明 Java 社区对于高效并发编程的需求,以及对于协程式编程的探索和实践,并且未来 Java 的发展可能会进一步引入更加高级的并发机制,为开发者提供更优雅和高效的并发编程体验。

二、Java Project Loom

Java Project Loom是Java语言的一个重要项目,它旨在改进Java虚拟机(JVM)的执行模型,以支持轻量级线程(Lightweight Threads),从而提高Java在处理并发和并行编程方面的性能和可伸缩性。本文将介绍Java Project Loom的背景、目标、主要特性以及对Java开发者和应用程序的影响。

1、背景

在Java开发中,线程(Thread)是一种常用的并发机制,允许程序以多个独立的执行路径同时运行。然而,传统的Java线程模型存在一些问题。每个线程都映射到操作系统的本地线程,这会导致创建和销毁线程的开销较大。而且,由于每个线程都会占用一定的内存空间,当并发程度较高时,大量线程的创建可能会导致内存消耗过大,甚至导致系统崩溃。

为了解决这些问题,Java Project Loom项目应运而生。

Java Project Loom的主要目标是引入一种轻量级线程实现,称为“Fibers”(纤程),以优化Java线程的管理和执行模型。Fibers是一种用户态线程,由Java虚拟机(JVM)和运行时系统进行管理,不再需要映射到操作系统的本地线程。这样,Fibers的创建和销毁开销将大大降低,并且可以在同一个操作系统线程内运行大量Fibers,从而减少内存消耗和提高性能。

2、主要特性

Java Project Loom带来了许多重要特性,其中最显著的是:

2.1. Fibers(纤程)

Fibers是Java Project Loom的核心特性。它们是一种轻量级的、用户态的线程实现,可以通过Fiber API进行创建、挂起、恢复和取消。与传统线程相比,Fibers的创建和销毁成本较低,并且可以高效地复用线程资源,使得应用程序可以拥有数千甚至数百万个并发执行的Fibers,而不会产生显著的内存开销。

2.2. Continuations(续体)

为了支持Fibers,Java Project Loom引入了Continuations的概念。Continuations允许在Fiber被挂起时保存其执行状态,并在需要时恢复到挂起的状态。这为Fibers的挂起和恢复提供了一种高效的机制,避免了传统线程上下文切换的开销。

2.3. Virtual Threads(虚拟线程)

Java Project Loom还引入了Virtual Threads的概念,它是一种对Fibers进行透明封装的机制。Virtual Threads可以根据应用程序的需求来动态地创建和管理Fibers,让开发者可以使用简单的编程模型处理大规模并发而无需担心线程管理细节。

2.4. Scoped Threads(作用域线程)

Scoped Threads是Java Project Loom的另一个重要特性,它允许Fibers在有限的作用域内运行。这样,Fiber在超出其作用域后将自动被销毁,从而避免了资源泄漏和线程管理的复杂性。

3、Project Loom的影响

Java Project Loom的推出将对Java开发者和应用程序产生深远的影响:

3.1. 更高的并发性能

通过引入轻量级的Fibers,Java Project Loom将使得Java应用程序可以更高效地处理大量并发任务,从而提供更高的并发性能和更好的可伸缩性。

3.2. 更低的内存消耗

由于Fibers不再需要映射到操作系统的本地线程,Java应用程序的内存消耗将显著降低,特别是在高并发场景下,这将对资源有限的环境和云计算平台尤为重要。

3.3. 更简洁的代码

Virtual Threads和Scoped Threads的引入将简化并发编程的代码逻辑,使得开发者可以更专注于业务逻辑而无需过多关注底层线程管理。

3.4. 更好的响应性

Java Project Loom的改进将使得Java应用程序更具响应性,特别是在高负载和高并发情况下,应用程序仍然能够快速响应用户请求。

总体而言,Java Project Loom是Java语言迈向更高并发性和更好性能的重要一步。通过引入Fibers和相关的特性,它将为Java开发者带来更强大的工具,使得开发高效、高并发的Java应用程序变得更加容易。随着Java生态系统的不断发展,Java Project Loom必将成为Java开发中不可或缺的重要组成部分。

4、Samples

许多应用程序不会直接使用 Thread API,而是使用 java.util.concurrent.ExecutorService和 Executors API。Executors API 已更新为 ExecutorServices 的新工厂方法,为每个任务启动一个新线程。虚拟线程足够便宜,可以为每个任务创建一个新的虚拟线程,永远不需要池化虚拟线程。

下面启动一个虚拟线程来打印消息。它调用join方法来等待线程终止。

Thread thread = Thread.ofVirtual().start(() -> System.out.println("Hello"));
thread.join();

下面是一个在休眠后启动虚拟线程将元素放入队列的示例。主线程阻塞在队列上,等待元素。

var queue = new SynchronousQueue<String>();
Thread.ofVirtual().start(() -> {
    try {
        Thread.sleep(Duration.ofSeconds(2));
        queue.put("done");
    } catch (InterruptedException e) { }
});
 
String msg = queue.take();

Thread.Builder API 也可用于创建 ThreadFactory。以下代码片段创建的 ThreadFactory 将创建名为“worker-0”、“worker-1”、“worker-2”等的虚拟线程。

ThreadFactory factory = Thread.ofVirtual().name("worker", 0).factory();

以下示例使用 Executors API 创建一个 ExecutorService,为每个任务启动一个新的虚拟线程。 该示例使用 try-with-resources 构造来确保 ExecutorService 在继续之前已终止。

ExecutorService定义了提交方法来执行任务。提交方法不会阻塞,而是返回一个可用于等待结果或异常的 Future 对象。接受任务集合的 Submit 方法会返回一个 Stream,该 Stream 会延迟填充代表结果的已完成的 Future 对象。

该示例还使用 invokeAll 和invokeAny 组合器方法 来执行多个任务并等待它们完成。

try (ExecutorService executor = Executors.newVirtualThreadExecutor()) {
      // Submits a value-returning task and waits for the result
    Future<String> future = executor.submit(() -> "foo");
    String result = future.join();
 
    // Submits two value-returning tasks to get a Stream that is lazily populated
    // with completed Future objects as the tasks complete
    Stream<Future<String>> stream = executor.submit(List.of(() -> "foo", () -> "bar"));
    stream.filter(Future::isCompletedNormally)
            .map(Future::join)
            .forEach(System.out::println);
 
    // Executes two value-returning tasks, waiting for both to complete
    List<Future<String>> results1 = executor.invokeAll(List.of(() -> "foo", () -> "bar"));
 
    // Executes two value-returning tasks, waiting for both to complete. If one of the
    // tasks completes with an exception, the other is cancelled.
    List<Future<String>> results2 = executor.invokeAll(List.of(() -> "foo", () -> "bar"), /*waitAll*/ false);
 
    // Executes two value-returning tasks, returning the result of the first to
    // complete, cancelling the other.
    String first = executor.invokeAny(List.of(() -> "foo", () -> "bar"));

}

三、SpringBoot如何使用协程

1. Project Loom

Java Project Loom旨在改进Java虚拟机的执行模型,其中核心概念是Fibers,也称为轻量级线程。Fibers提供了一种轻量级的线程模型,可以高效地创建和管理大量的并发任务,而不像传统线程那样消耗大量的系统资源。虽然Spring Boot本身没有集成Project Loom,但可以在Spring Boot应用程序中使用Project Loom来实现协程。为此,你需要使用Java 17或更新版本,并引入Project Loom的依赖。

以下是一个简单的示例,展示如何使用Project Loom的Fibers来实现协程:

public class CoroutineExample {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newVirtualThreadExecutor();

        SubmissionPublisher<String> publisher = new SubmissionPublisher<>(executorService, 1);

        // Subscribe to the publisher
        publisher.subscribe(new SimpleSubscriber());

        // Publish some data
        for (int i = 0; i < 5; i++) {
            publisher.submit("Data " + i);
        }

        // Close the publisher and wait for the subscribers to finish
        publisher.close();
        executorService.awaitTermination(1, TimeUnit.SECONDS);
        executorService.shutdown();
    }
}

2. Quasar框架

Quasar是一个基于Java的协程库,它提供了协程的实现和管理。使用Quasar,你可以在Spring Boot应用程序中创建协程来处理并发任务。

要使用Quasar,你需要将其作为依赖项添加到Spring Boot项目中。然后,你可以使用Quasar提供的API来创建、挂起和恢复协程。

以下是一个简单的示例,展示如何在Spring Boot应用程序中使用Quasar实现协程:

@FiberSpringBootApplication
    public class CoroutineExample {

        public static void main(String[] args) throws InterruptedException {
            new Fiber<Void>(() -> {
                for (int i = 0; i < 5; i++) {
                    System.out.println("Data " + i);
                    try {
                        Fiber.sleep(1000);
                    } catch (SuspendExecution | InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start().join();
        }
    }

四、第三方集成

4.1.Vert.x

Vert.x是一个基于事件驱动的响应式框架,它可以让开发者使用Java或其他JVM语言编写高性能的异步应用。Vert.x已经开始尝试集成Java虚拟线程,目前有一个虚拟线程孵化器项目,它包含了一个async/await的实现。这个项目可以让开发者使用类似于JavaScript或C#的语法来编写异步代码,而不需要使用回调或者Future。

Vert.x是一个用于构建响应式、高性能、可伸缩的应用程序的工具包和框架。它基于Java语言,提供了一个异步编程模型,使得开发者可以轻松地构建事件驱动的、非阻塞的应用程序。

主要特点和优势:

  1. 响应式和非阻塞:Vert.x采用了事件循环和异步编程模型,允许应用程序以非阻塞方式处理请求和事件,从而实现高吞吐量和低延迟。
  2. 多语言支持:尽管Vert.x是用Java构建的,但它还支持其他语言,如Kotlin、Groovy和JavaScript。这使得开发者可以使用自己喜欢的语言来编写应用程序。
  3. 内置集群支持:Vert.x内置了集群支持,可以在多个节点上运行应用程序实例,从而实现水平扩展和高可用性。
  4. 组件丰富:Vert.x提供了丰富的组件和库,包括HTTP服务器、WebSocket、消息总线、数据库客户端等,使得开发者能够快速构建各种类型的应用程序。
  5. 轻量级:Vert.x是一个轻量级框架,不像一些大型框架那样臃肿,可以在资源有限的环境中运行。
  6. 社区活跃:Vert.x拥有一个活跃的开源社区,持续开发和更新,使得它保持在技术前沿,并且有很多贡献者为其提供支持和扩展。

Vert.x适用于构建各种类型的应用程序,特别是需要高性能、高并发和实时性的场景。它可以用于构建Web应用程序、API服务、实时通信应用、IoT应用等。如果您对响应式编程和高性能的应用程序开发感兴趣,Vert.x值得一试。

4.2.Jetty

Jetty是一个轻量级的Java web服务器和servlet容器。Jetty也已经支持了Java虚拟线程。

Java 19 中引入的虚拟线程在 Jetty 12 中受支持,因为它们分别从 10.11.10 和 0.12.11 开始在 Jetty 0 和 Jetty 12 中得到支持。

当 JVM 支持虚拟线程并在 Jetty 中启用时(请参阅嵌入式用法和独立用法),将使用虚拟线程调用应用程序,这允许它们使用简单的阻塞 API,但具有虚拟线程的可伸缩性优势。

4.3.Tomcat

Tomcat是一个广泛使用的Java web服务器和servlet容器。Tomcat也支持Java虚拟线程,并在版本中有相关说明。

4.4.Helidon

Helidon是一个微服务框架,它提供了两种编程模型:Helidon SE和Helidon MP。Helidon SE是一个基于函数式编程的轻量级框架,它支持Reactive Streams和非阻塞IO。Helidon MP是一个基于标准化的注解驱动的框架,它支持MicroProfile API。Helidon也已经集成了Java虚拟线程,并提供了一些示例代码来展示如何使用它。

4.5.Quarkus

Quarkus是一个为云原生应用而生的全栈框架,它提供了高性能、低内存占用、快速启动和热重载等特性。Quarkus也已经支持了Java虚拟线程,并提供了一些文档和指南来介绍如何使用它。


如果文章对你有帮助,欢迎关注+点赞!!!

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

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

相关文章

【C++】map和set在OJ中的应用

文章目录 前言1. 剑指 Offer &#xff1a; 复杂链表&#xff08;带随机指针&#xff09;的复制1.1 思路分析&#xff08;利用map搞&#xff09;1.2 AC代码 2. 前K个高频单词2.1 思路1AC代码2.2 思路2AC代码2.3 思路3AC代码 3. 两个数组的交集3.1 思路分析3.2 AC代码 前言 上一篇…

AI和ChatGPT:人工智能的奇迹

AI和ChatGPT&#xff1a;人工智能的奇迹 引言什么是人工智能&#xff1f;ChatGPT&#xff1a;AI的语言之王ChatGPT的工作原理ChatGPT的优势和挑战AI和ChatGPT的未来展望结论 引言 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一项令人兴奋的…

收集到大量的名片怎么转为excel?

来百度APP畅享高清图片 参加完展会或集体会议&#xff0c;是不是收了一大堆名片&#xff0c;保管起来超级麻烦&#xff0c;还容易丢三落四&#xff1f;别急&#xff0c;我们有办法&#xff01;把名片转成电子版保存到电脑上就完美啦&#xff01;但要是名片数量有点多&#xff0…

Linux文本三剑客之awk

目录 前言 awk 1.认识awk 2.使用awk 2.1语法 2.2常用命令选项 2.3awk变量 2.3.1内置变量 2.3.2自定义变量 2.4printf命令 awk例题 前言 awk、grep、sed是linux操作文本的三大利器&#xff0c;合称文本三剑客&#xff0c;也是必须掌握的linux命令之一。三者的功能都是…

什么是全局代理,手机怎么设置全局代理

目录 什么是全局代理 全局代理的优缺点 优点 缺点 手机怎么设置全局代理 注意事项 总结 在计算机网络和信息安全中&#xff0c;全局代理是一种常用的技术手段&#xff0c;用于将网络流量通过代理服务器进行转发和处理。本文将介绍什么是全局代理&#xff0c;探讨全局代理…

Stable Diffusion - Candy Land (糖果世界) LoRA 提示词配置与效果展示

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132145248 糖果世界 (Candy Land) 是一个充满甜蜜和奇幻的地方&#xff0c;由各种各样的糖果和巧克力构成。在糖果世界&#xff0c;可以看到&…

el-select 三级联动

一、效果图 二、思路&#xff1a;先请求一级select数据&#xff0c;通过选中的id请求二级数据&#xff0c;以此类推&#xff01; 三、代码 <template><div><el-card><el-form :inline"true"><el-form-item label"一级">&l…

如何用正确的姿势监听Android屏幕旋转

作者&#xff1a;37手游移动客户端团队 背景 关于个人&#xff0c;前段时间由于业务太忙&#xff0c;所以一直没有来得及思考并且沉淀点东西&#xff1b;同时组内一个个都在业务上能有自己的思考和总结&#xff0c;在这样的氛围下&#xff0c;不由自主的驱使周末开始写点东西&…

安卓:UDP通信

目录 一、介绍 网络通信的三要素&#xff1a; &#xff08;1&#xff09;、IP地址&#xff1a; IPv4: IPv6: IP地址形式&#xff1a; IP常用命令&#xff1a; IP地址操作类: &#xff08;2&#xff09;、端口&#xff1a; &#xff08;3&#xff09;、协议: UDP协…

【图论】单源最短路

算法提高课笔记。&#xff08;本篇还未更新完… 目录 单源最短路的建图方式例题热浪题意思路代码 信使题意思路代码 香甜的黄油题意思路代码 最小花费题意思路代码 最优乘车题意思路代码 昂贵的聘礼题意思路代码 单源最短路的建图方式 最短路问题可以分为以下两类&#xff1a…

红队钓鱼技术之LNK快捷方式

简介 lnk文件是用于指向其他文件的一种文件。这些文件通常称为快捷方式文件&#xff0c;通常它以快捷方式放在硬盘上&#xff0c;以方便使用者快速的调用。lnk钓鱼主要将图标伪装成正常图标&#xff0c;但是目标会执行shell命令 步骤 1.编写shell命令 首先新建一个文本文件t…

解码大众全新数字高尔夫8汽车CAN FD行驶功能电气架构

据在大众原厂的伙伴介绍&#xff0c;全新数字高尔夫8将在11月上市销售&#xff0c;目前高尔夫8在行驶功能电气架构上采用的CAN FD&#xff0c;在多媒体这一块采用的以太网&#xff0c;后续估计大部分类似同样MQBEvo平台的车型均会复制升级过来&#xff0c;那么&#xff0c;未来…

An unexpected error has occurred. Conda has prepared the above report

今日在服务器上创建anaconda虚拟环境的时候&#xff0c;出现了如下报错 An unexpected error has occurred. Conda has prepared the above report 直接上解决方案 在终端中输入如下指令 conda config --show-sources 如果出现以下提示&#xff0c;说明多了一个文件 输入以下…

基于CentOS 7构建LVS-DR集群

DIPVIPRIPClient192.169.41.139 LVS 192.168.41.134192.169.41.10RS1192.168.41.135RS2192.168.41.138 要求&#xff1a; node4为客户端&#xff0c;node2为LVS&#xff0c;node3和node4为RS。 1.配置DNS解析&#xff08;我这里使用本地解析&#xff09; 192.168.41.134 www.y…

谷粒商城第十天-获取分类属性分组(前端组件抽取父子组件交互)

目录 一、总述 1.1 前端思路 1.2 后端思路 二、前端部分 2.1 将分类树前端代码抽取成一个组件 2.2 使用elementUI的组件实现左右组件功能 2.3 使用事件机制进行组件通信 三、后端部分 四、总结 一、总述 说一下今天需要实现一个什么样子的功能&#xff1a; 很简单&am…

Vue2:组件高级(上)

Vue2&#xff1a;组件高级&#xff08;上&#xff09; Date: May 20, 2023 Sum: 组件样式冲突、data函数、组件通信、props、组件生命周期、vue3.x中全局配置axios 目标&#xff1a; 能够掌握 watch 侦听器的基本使用 能够知道 vue 中常用的生命周期函数 能够知道如何实现组…

基于自组织竞争网络的患者癌症发病预测(matlab代码)

1.案例背景 1.1自组织竞争网络概述 前面案例中讲述的都是在训练过程中采用有导师监督学习方式的神经网络模型。这种学习方式在训练过程中,需要预先给网络提供期望输出,根据期望输出来调整网络的权重,使得实际输出和期望输出尽可能地接近。但是在很多情况下,在人们认知的过程中…

分布式规则引擎框架的设计

MirAIe 规则引擎是一个可扩展且可扩展的规则引擎框架&#xff0c;允许用户对多个活动进行分组和自动化。 过去几年&#xff0c;在开发MirAIe 物联网平台时&#xff0c;我们意识到需要一个可扩展、可扩展的规则引擎框架。规则引擎使您能够对各种操作进行分组、管理和自动化&…

git【潦草学习】

初始配置git 查询版本号 初次使用git前配置用户名与邮箱地址 git config --global user.name "your name" git config --global user.email "your email" git config -l 发现最后两行多出了用户名和邮箱&#xff0c;说明配置成功

对指针变量引用以及自定义类型引用的认识

#include <iostream> using namespace std; #include <iomanip>typedef int G[10]; //自定义类型void test(int* p); // void test_0(int &p); //表明p是一个int型变量的别名 void test_1(G &pG); //表明pG是一个G类型变量的别名 void test_2(int*…