2天时间,聊今年最热的 Agent、上下文工程、AI 产品创新等话题。2025 年最后一场~ 了解详情
写点什么

JEP 481:作用域值 API 的第 3 个预览版随 JDK 23 发布,带来关键增强

  • 2024-08-12
    北京
  • 本文字数:1628 字

    阅读完需:约 5 分钟

JEP 481:作用域值API的第3个预览版随JDK 23发布,带来关键增强

JEP 481(作用域值第 3 个预览版)——之前称为范围局部变量(孵化)——提供了第三次预览。该版本只有一个变化,旨在从之前的一轮孵化和两轮预览之外获得额外的经验和反馈:随 JDK 22 交付的 JEP 464(作用域值第 2 个预览版)、随 JDK 21 交付的 JEP 446(作用域值预览版)以及随 JDK 20 交付的 JEP 429(作用域值孵化)。该特性支持在线程内部和线程之间共享不可变数据。


在 JDK 23 中重新预览的作用域值 API 修改了ScopedValue.callWhere方法。现在,这个方法的操作参数是一个函数式接口。它允许 Java 编译器推断是否可能抛出检查异常。因此,ScopedValue.getWhere这个方法就不再需要了,而且已经删除。在频繁共享数据的场景中,这会使代码更简洁,而且性能更好。


作用域值使方法能够与其调用者和子线程共享不可变数据。与线程局部变量相比,这可以简化数据流的管理和推断。而且,它们的空间和时间成本更低,特别是在与虚拟线程(JEP 444)和结构化并发(JEP 480)结合使用时。


不过,Java 1.2 中引入的线程局部变量一直是一个简化同一线程内方法间数据共享的传统方法。尽管已经使用了很长时间,但它还是有一些缺点。一个主要的问题是它们毫无约束的可变性,任何代码都可以随时更改线程局部变量的值,这可能导致潜在的不一致。另一个缺点是它们的寿命不受限制;如果开发人员忘记调用remove方法,值的保存时长可能会超过所需的时长,而这通常会导致内存泄漏。此外,跨线程继承线程局部变量会显著增加开销,因为每个子线程都必须为先前在父线程中写入的每个线程局部变量分配存储空间,这会对性能产生负面影响。


作用域值解决了这个问题,它确保数据是不可变的,并且只能在定义好的作用域中访问。这增强了安全性和性能。


为了说明作用域值的好处,考虑下这样一个 Web 框架,它的上下文需要在不同的方法之间共享,而又不需要显式地将其作为参数传递。使用线程局部变量,该框架可能是这样的:


class Framework {
private final static ThreadLocal<FrameworkContext> CONTEXT = new ThreadLocal<>();
void serve(Request request, Response response) { var context = createContext(request); CONTEXT.set(context); Application.handle(request, response); }
public PersistedObject readKey(String key) { var context = CONTEXT.get(); var db = getDBConnection(context); return db.readKey(key); }}
复制代码


使用作用域值,其实现会变得更加简洁、高效:


class Framework {
private final static ScopedValue<FrameworkContext> CONTEXT = ScopedValue.newInstance();
void serve(Request request, Response response) { var context = createContext(request); ScopedValue.runWhere(CONTEXT, context, () -> Application.handle(request, response)); }
public PersistedObject readKey(String key) { var context = CONTEXT.get(); var db = getDBConnection(context); return db.readKey(key); }}
复制代码


使用线程局部变量,当框架调用用户代码以及当用户代码回调框架方法时,不需要将FrameworkContext作为方法的参数进行传递。线程局部变量是作为一个隐藏的方法参数:线程调用Framework.serve中的CONTEXT.set。然后,Framework.readKey中的CONTEXT.get自动就可以看到CONTEXT的本地副本。实际上,ThreadLocal字段充当了一个键,用于查找当前线程的FrameworkContext值。另一方面,使用作用域值简化了这个过程。它消除了可变状态,并且确保上下文只能在runWhere方法定义好的范围内访问,从而提供了一种更健壮且性能更好的方法。总之,作用域值 API 显著增强了 Java 中跨方法和线程共享数据的方式,促进了更好的编码实践,并提高了应用程序的性能。它非常符合现代并发模型,特别是当虚拟线程出现之后,它为开发人员处理高并发应用程序提供了一个重要的选项。


原文链接:

https://www.infoq.com/news/2024/07/jep-481-enhanced-scoped-values/

2024-08-12 08:006045

评论

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

宿舍晚上温度高,那是你没听“鬼故事”

华为云开发者联盟

人工智能 AI 华为云 modelarts

数据库设计

Jayli

数据库

当地铁站都比你更努力

escray

学习 面试

代理模式详解

大头星

带你全面认识 Linux

简爱W

Python处理视频文件的实用姿势

程一初

Python 自动化 办公

影响音视频延迟的关键因素(三): 传输、渲染

ZEGO即构

buffer API RTC sdk

前端科普系列(4):Babel —— 把 ES6 送上天的通天塔

vivo互联网技术

Java 大前端 ES6

LeetCode1160---拼写单词---Easy

书旅

LeetCode

Python1024办公自动化系列

程一初

Python 自动化 办公

如何与面试官更好的沟通

escray

学习 面试

Python处理Word文件的实用姿势

程一初

Python 自动化 办公

Python处理Excel文件的实用姿势

程一初

Python 自动化 办公

前端科普系列(3):CommonJS 不是前端却革命了前端

vivo互联网技术

Java 大前端 脚本

MySQL从入门到精通

书旅

MySQL 索引

Python处理PDF的实用姿势

程一初

Python 自动化 办公

Python处理图像文件的实用姿势

程一初

Python 自动化 办公

Truncate用法详解

Simon

MySQL

解读 Reference

浮白

ThreadLocal Reference ReferenceQueue Finalizer WeakHashMap

Python处理PPT文件的实用姿势

程一初

Python 自动化 办公

前端科普系列(2):Node.js 换个角度看世界

vivo互联网技术

node.js 大前端

LeetCode680-验证回文字符串 Ⅱ-Easy

书旅

LeetCode

业务架构是什么?

周金根

BIZBOK 业务架构 IT帮 周金根

Axure导出为PDF

波菠菜

并发神器CSP的前世今生

soolaugust

并发编程 并发 Go 语言

从《三体》到“中美科技战”,3分钟理解“网络”D丝为什么要迎娶“算力”白富美

华为云开发者联盟

数据 网络 芯片 算力 三体

MacOS 环境下 Python 访问 MySQL

李绍俊

Python处理邮件和机器人的实用姿势

程一初

Python 自动化 办公

JavaScript 测试系列实战(一):使用 Jest 和 Enzyme 测试 React 组件

图雀社区

单元测试 自动化测试 Jest

Python处理音频文件的实用姿势

程一初

Python 自动化 办公

【程序员自救指南】中关村保洁大叔的一句话竟然帮我转正了

华为云开发者联盟

服务器 数字化 华为云 企业上云 云服务器

JEP 481:作用域值API的第3个预览版随JDK 23发布,带来关键增强_编程语言_A N M Bazlur Rahman_InfoQ精选文章