【ArchSummit】如何通过AIOps推动可量化的业务价值增长和效率提升?>>> 了解详情
写点什么

JEP 428:结构化并发,简化 Java 多线程编程

作者:A N M Bazlur Rahman

  • 2022-06-17
  • 本文字数:2284 字

    阅读完需:约 7 分钟

JEP 428:结构化并发,简化Java多线程编程

JEP 428,即结构化并发(孵化器阶段),已经从 Proposed 状态进入到 Target 状态。在 Project Loom 的框架下,这个 JEP 提议引入一个库,将在不同线程中运行的多个任务视为原子操作,以此来简化多线程编程。它可以简化错误处理和取消操作,提高可靠性,并增强可观察性。这个 API 仍然在孵化当中。


开发人员可以使用 StructuredTaskScope 类来组织他们的并发代码,这个类将把一组子任务视为一个单元。子任务通过单独的线程创建,然后连接成一个单元,也可以作为一个单元进行取消。子任务的异常或执行结果将由父任务进行聚合和处理。让我们来看一个例子:


Response handle() throws ExecutionException, InterruptedException {   try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {       Future<String> user = scope.fork(() -> findUser());       Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join(); // 连接 scope.throwIfFailed(); // 抛出错误
// 聚合结果 return new Response(user.resultNow(), order.resultNow()); }}
复制代码


上面的 handle()方法表示服务器应用程序的一个任务。它创建了两个子任务来处理传入的请求。与 ExecutorService.submit()一样,StructuredTaskScope.fork()接受 Callable 作为参数,并返回 Future。与 ExecutorService 不同的是,返回的 Future 不是通过 Future.get()来连接的。这个 API 运行在 JEP 425 之上——虚拟线程(预览阶段),发布目标也为 JDK 19。


上面的例子使用了 StructuredTaskScope API,如果要在 JDK 19 上运行它们,必须添加 jdk.incubator.concurrent 模块,同时要启用预览功能来使用虚拟线程。


使用下面的命令编译上述代码:


javac --release 19 --enable-preview --add-modules jdk.incubator.concurrent Main.java
复制代码


运行程序也需要提供相同的标志:


java --enable-preview --add-modules jdk.incubator.concurrent Main
复制代码


不过,我们也可以使用源代码启动器直接运行它,命令应该是这样的:


java --source 19 --enable-preview --add-modules jdk.incubator.concurrent Main.java
复制代码


jshell 也是可用的,但也需要启用预览功能:


jshell --enable-preview --add-modules jdk.incubator.concurrent
复制代码


结构化并发带来了很多好处。它为调用者方法及其子任务创建了一种父子关系。例如,在上面的例子中,handle()任务是父,它的子任务 findUser()和 fetchOrder()是子。结果,整个代码块变成了原子代码。它通过线程转储中的任务层次结构来提供可观察性。它还可以在错误处理中实现短路,如果其中一个子任务失败,其他未完成的任务将被取消。如果父任务的线程在 join()调用之前或期间被中断,两个分支将在作用域退出时自动取消。这让并发代码的结构变得更加清晰,开发人员现在可以推理和跟踪代码,就好像它们是在单线程环境中运行。


早期的程序流程普遍使用 GOTO 语句来控制,代码十分混乱,这种意大利面条式的代码难以阅读和调试。随着编程范式的成熟,编程社区认识到 GOTO 语句是有害的。1969 年,以《计算机编程的艺术》一书而闻名的计算机科学家 Donald Knuth 表示,没有 GOTO 也可以高效地编写程序。后来,结构化编程的出现解决了所有这些缺点。看一下下面的例子:


Response handle() throws IOException {   String theUser = findUser();   int theOrder = fetchOrder();   return new Response(theUser, theOrder);}
复制代码


上面的代码是结构化代码的一个例子。在单线程环境中,handle()方法被调用时将按顺序执行。fetchOrder()方法不会在 findUser()方法之前启动。如果 findUser()方法失败,下面的方法根本不会启动,handle()方法将隐式失败,这反过来确保了原子操作成功或不成功。它提供了 handle()方法及其子方法之间的父子关系,遵循错误传播的规则,并在运行时提供调用堆栈信息。


然而,这种方法和推理并不适用于我们当前的线程编程模型。例如,如果我们想用 ExecutorService 改写上述的代码,就像这样:


Response handle() throws ExecutionException, InterruptedException {   Future<String>  user  = executorService.submit(() -> findUser());   Future<Integer> order = executorService.submit(() -> fetchOrder());   String theUser  = user.get();   // 连接findUser   int theOrder = order.get();  // 连接fetchOrder   return new Response(theUser, theOrder);}
复制代码


ExecutorService 中的子任务独立运行,可能成功或失败。即使父任务被中断,中断也不会被传播到子任务,因此会造成泄漏。它没有了父关系。由于父任务和子任务将出现在线程转储不相关的线程调用堆栈上,因此调试也变得困难。尽管代码看起来具有逻辑结构,但这种结构只停留在开发人员的头脑中,而不是在执行过程中。所以,它们是非结构化的并发代码。


通过观察非结构化并发代码存在的这些问题,Martin Sústrik 在他的博文中创造了“结构化并发”这个术语,然后 Nathaniel J. Smith 在他关于结构化并发的文章中推广了这个术语。关于结构化并发,Oracle 技术咨询成员、Loom 项目负责人 Ron Pressler 在 InfoQ 的一个播客中说道:


结构化的意思是,如果你生成了什么东西,你必须等待并连接它。这里的“结构”与它在结构化编程中的含义相似。代码的块结构反映了程序的运行时行为。因此,就像结构化编程提供了顺序控制流保证,结构化并发也为并发提供了同样的保证。有兴趣深入了解结构化并发及其背景故事的开发者可以收听 InfoQ 的博客,或者观看 Ron Pressler 在YouTube上的分享以及Inside Java的文章。


原文链接

JEP 428: Structured Concurrency to Simplify Java Multithreaded Programming

2022-06-17 08:084714

评论

发布
暂无评论
发现更多内容

基于 gh-ost 的在线 Schema 变更

Bytebase

MySQL 数据库

RT-Thread记录(十五、I/O 设备模型之SPI设备)

矜辰所致

RT-Thread 8月月更 I/O设备模型

测试 SAP 电商云 Spartacus UI 3.4.x 和 4.3.x 的 guest checkout 功能

Jerry Wang

typescript 前端 angular Spartacus 8月月更

【数据结构实践】简单实现Python自定义队列

迷彩

数据结构 算法 队列 8月月更

开源一夏 |log4j2漏洞复现及修复

六月的雨在InfoQ

开源 Log4j 2 Log4j2 漏洞 8月月更

2021年中国智能驾驶行业洞察

易观分析

自动化 智能驾驶

死磕它七年“腾讯限量版”Java架构笔记,要个40k不过分吧?

Geek_Yin

编程 程序员 涨薪 架构师 #java

Alibaba最新神作!耗时182天肝出来1015页分布式全栈手册太香了

退休的汤姆

Java 程序员 分布式 面经 秋招

五问五答:第三方风险管理

SEAL安全

网络安全 风险管理 安全风险 软件供应链安全

逆向工程:揭示Google Colab未公开的秘密

OneFlow

机器学习 深度学习 模型

秋招!面试十次字节/美团失败总结的《520道LeetCode题Java版答案》

退休的汤姆

Java 程序员 面经 Java工程师 秋招

长阳土家族自治县政府与升哲科技达成战略合作

SENSORO

新基建 智慧城市 AIOT

如何通过OpenHarmony的音频模块实现录音变速功能?

OpenHarmony开发者

OpenHarmony

2022 全国大学生操作系统大赛圆满落幕 龙蜥推动人才培养与产业发展深度融合

OpenAnolis小助手

开源 操作系统 龙蜥社区 设计比赛

阿里云 ACK One 多集群管理全面升级:多集群服务、多集群监控、两地三中心应用容灾

阿里巴巴云原生

阿里云 容器 分布式 云原生 集群

TDengine 3.0 三大创新详解

TDengine

数据库 tdengine 时序数据库

泛谈传统运营商借鉴电商模式

鲸品堂

电商 运营商 通信运营商 电信运营商

向量数据库公司 Zilliz 完成 6000 万美元 B+ 轮融资

Zilliz

融资 数据库·

开发者测评:阿里云 ACR 与其他的镜像仓库到底有什么不同?

阿里巴巴云原生

阿里云 云原生 ACR

非关系型数据库 Redis 核心内容

苏玖

数据库 nosql redis redis持久化 8月月更

Java基础知识总结--事务失效的12种场景

阿婷

Java 后端 事务 8月月更

升哲科技荣获2022年“中国IC设计成就奖”

SENSORO

物联网 芯片

“智慧”有为!AntDB数据库助力某省高速率先完成自主可控建设

亚信AntDB数据库

AntDB 国产数据库 aisware antdb

一箭双雕!刷完阿里P8架构师spring学习笔记+源码剖析,涨薪8K

Geek_Yin

编程 程序员 springboot #java Spring Java

秒合约交易APP系统开发源码搭建

开发微hkkf5566

团队管理之不轻易责备

蛋先生DX

管理 团队 团队氛围

绿色数据中心案例介绍:阿里巴巴、华为、电信、移动……

蓝海大脑GPU

数字无限 云领未来 | 华为云&赛意信息线上直播约定您

Geek_2d6073

华为云CDN同舟计划

科技云未来

2022年密码测评理论与关键技术前沿论坛|海泰方圆分享密码应用改造典型方案

电子信息发烧客

数字藏品APP开发定制

开源直播系统源码

软件开发 数字藏品 数字藏品开发 数字藏品系统

JEP 428:结构化并发,简化Java多线程编程_语言 & 开发_InfoQ精选文章