属于Java的协程终于来了!

简介: 属于Java的协程终于来了!
  • 关于虚拟线程
  • 更高的吞吐量
  • 如何启用虚拟线程?

OpenJDK 的 JEP 425 :虚拟线程(预览版)功能提案显示:Java 平台将引入虚拟线程特性(期待已久的协程)。虚拟线程是轻量级线程,可显著地减少编写、维护和观察高吞吐量并发应用程序的工作量。

Java 开发人员一直依赖线程作为并发服务器应用程序的构建块,每个方法中的语句都在一个线程内执行,每个线程提供一个堆栈来存储局部变量和协调方法调用,以及报错时的上下文捕获。线程是 Java 的并发单元,也是 Java 工具的核心基础:调试器逐步执行线程方法中的语句,分析器则可视化多个线程的行为。

目前,JDK 将其平台线程实现为操作系统 (OS) 线程的包装器,JDK 中每个实例都是一个平台线程,平台线程在底层操作系统线程上运行 Java 代码 ,并在代码的整个生命周期内捕获 OS 线程。平台线程数受限于 OS 线程数,而 OS 线程的成本很高,不能占用太多。因此,目前 JDK 的这种线程实现方法限制了其应用程序的吞吐量,使吞吐量远低于硬件支持的水平。

2.png

关于虚拟线程

虚拟线程java.lang.Thread是在底层操作系统线程(OS 线程)上运行 Java 代码,但在代码的整个生命周期内不捕获 OS 线程的实例。这意味着许多虚拟线程可以在同一个 OS 线程上运行 Java 代码,从而有效地共享它。

虚拟线程是由 JDK 而不是操作系统提供的线程的轻量级实现,也是用户模式线程 的一种形式。用户模式线程在 Java 的早期版本中被称为“绿色线程”,当时操作系统线程的概念还不够成熟和普及, Java 的所有绿色线程都共享一个 OS 线程(M:1 调度),随着线程概念的发展,绿色线程最终被现在的平台线程超越,实现为 OS 线程的包装器(1:1 调度),而最新引入的虚拟线程采用 M:N 调度,其中大量 (M) 虚拟线程被调度为在较少数量 (N) 的 OS 线程上运行。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能。

项目地址:https://github.com/YunaiV/ruoyi-vue-pro

更高的吞吐量

开发者可以选择使用虚拟线程还是平台线程,但虚拟线程在高吞吐量的服务器应用程序中表现更好。比如下面这段休眠一秒钟的代码就创建了大量的虚拟线程,程序首先获得一个 ExecutorService,它为每个提交的任务创建一个新的虚拟线程,然后提交 10000 个任务并等待所有任务完成:

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
}  // executor.close() is called implicitly, and waits

现代硬件可以很容易地支持 10000 个虚拟线程同时运行这样的代码。如果该程序使用为每个任务都创建一个新平台线程的 ExecutorService,例如 Executors.newCachedThreadPool() , 那么它将尝试创建 10000 个平台线程,也就意味着 10000 个 OS 线程,那么这个程序在大多数操作系统上都会崩溃。又或者这个程序使用从池中获取平台线程的 ExecutorService,如 Executors.newFixedThreadPool(200),也好不到哪去。ExecutorService 将创建 200 个平台线程供这 10000 个任务共享,任务将按顺序运行而不是同时运行,程序需要很长时间才能跑完。

对于上述程序来说,具有 200 个平台线程的池只能实现每秒 200 个任务的吞吐量,而虚拟线程可以实现大约每秒 10000 个任务的吞吐量(在充分预热之后)。此外,如果将示例程序中的 10000 更改为 1,000,000 ,则程序将提交 1,000,000 个任务,创建 1,000,000 个并发运行的虚拟线程,并且(在充分预热后)达到大约 1,000,000 个任务/秒的吞吐量。

总而言之,虚拟线程不是更快的线程 —— 它们运行代码的速度并不比平台线程快。它们的存在是为了提供规模(更高的吞吐量),而不是速度(更低的延迟)。

基于微服务的思想,构建在 B2C 电商场景下的项目实战。核心技术栈,是 Spring Boot + Dubbo 。未来,会重构成 Spring Cloud Alibaba 。

项目地址:https://github.com/YunaiV/onemall

如何启用虚拟线程?

目前虚拟线程在其他多线程语言中被广泛使用(例如 Go 中的协程 和 Erlang 中的进程,在 C++ 中也是一个稳定特性),但在 Java 中还是一个预览 API,默认禁用。如要在 JDK XX 上尝试该功能,则必须通过以下方法启用预览 API:

  • 使用 javac --release XX --enable-preview Main.java 编译程序,并使用 java --enable-preview Main 运行
  • 使用源代码启动器时,使用 java --release XX --enable-preview Main.java 运行程序
  • 使用 jshell 时,用 jshell --enable-preview 启动

有关虚拟线程的更多信息可在 OpenJDK 的 JDK Issue-8277131 中查看,目前该提案于 2021/11/15 创立,目前还处于 JEP 流程的第一阶段,距离稳定版本还需要一段时间。

相关文章
|
5月前
|
Java 开发者
Java一分钟之-Quasar:协程库
【6月更文挑战第12天】Quasar是Java的高性能协程库,通过字节码增强实现轻量级并发模型——协程和通道,降低并发处理的复杂性和资源消耗。本文探讨了Quasar的常见问题,如内存泄漏、死锁和过度使用,提出相应避免策略,并提供了一个简单的协程间数据交换的代码示例。正确使用Quasar能提升程序性能和可维护性。
270 1
|
Java 调度 数据库
java 用协程 实现 简单下订单功能
java 用协程 实现 简单下订单功能
121 0
|
3月前
|
Java 程序员 调度
【JAVA 并发秘籍】进程、线程、协程:揭秘并发编程的终极武器!
【8月更文挑战第25天】本文以问答形式深入探讨了并发编程中的核心概念——进程、线程与协程,并详细介绍了它们在Java中的应用。文章不仅解释了每个概念的基本原理及其差异,还提供了实用的示例代码,帮助读者理解如何在Java环境中实现这些并发机制。无论你是希望提高编程技能的专业开发者,还是准备技术面试的求职者,都能从本文获得有价值的见解。
64 1
|
1月前
|
关系型数据库 MySQL Java
java协程操作mysql数据库
本文介绍了如何在Java项目中使用虚拟线程和协程操作MySQL数据库,并通过代码示例展示了如何利用CompletableFuture实现非阻塞数据库连接和操作。
29 2
java协程操作mysql数据库
|
3月前
|
C# 开发者 数据处理
WPF开发者必备秘籍:深度解析数据网格最佳实践,轻松玩转数据展示与编辑大揭秘!
【8月更文挑战第31天】数据网格控件是WPF应用程序中展示和编辑数据的关键组件,提供排序、筛选等功能,显著提升用户体验。本文探讨WPF中数据网格的最佳实践,通过DevExpress DataGrid示例介绍其集成方法,包括添加引用、定义数据模型及XAML配置。通过遵循数据绑定、性能优化、自定义列等最佳实践,可大幅提升数据处理效率和用户体验。
61 0
|
5月前
|
Java Maven 开发者
Java一分钟之-Quasar协程:Java中的协程支持
【6月更文挑战第17天】Java并发处理中,Quasar库引入轻量级的纤程(Fiber)以提升效率。纤程在单线程内并发执行,减少资源消耗。常见问题包括内存泄漏、死锁和过度使用。要避免这些问题,需正确管理资源,使用协程友好的同步原语,以及合理规划纤程创建。安装Quasar时,在Maven项目中添加依赖。示例代码展示了如何启动纤程和通过通道进行异步通信。理解原理和最佳实践是关键。
143 7
|
4月前
|
Java Go 调度
Java演进问题之协程和线程在资源占用和切换速度上不同如何解决
Java演进问题之协程和线程在资源占用和切换速度上不同如何解决
|
6月前
|
Java 程序员 调度
JAVA 并发编程 进程、线程、协程
程序是静态的,程序运行后变为一个进程,一个进程内部可以有多个线程同时执行。进程是所有线程的集合,每一个线程是进程中的一条执行路径
|
Java API 调度
Java 中如何实现协程?
Java 中如何实现协程?
|
Java Go API
JDK21要来了,协程可以给Java带来什么
今年9月份,Java会最新的LTS版本的发布会带来一项重磅更新:协程在此之前,在JDK19中协程已经作为一个预览版的功能被放在了JDK中,本文将探讨一下使用协程后究竟可以为我们现在的Java应用解决什么问题,以及现在成熟的协程实现(Kotlin/Go),在最后会基于JDK20的协程实现分析下JDK部分的源码。协程是什么协程其实是很古老的概念,1963年就被提出。协程是一种协作式的程序执行流,只有当
4247 0
JDK21要来了,协程可以给Java带来什么