JEP 481:Scoped Values(第三次预览)
JEP 481,即Scoped Values(第三次预览),已为JDK 23完成。该JEP在经历了孵化阶段和两次预览阶段后,提供了第三次预览版本,旨在通过引入一个变更来获取更多的经验和反馈。此前的相关JEP包括:
- JEP 464(JDK 22):Scoped Values(第二次预览)
- JEP 446(JDK 21):Scoped Values(预览)
- JEP 429(JDK 20):Scoped Values(孵化)
Scoped Values 允许在线程内部和跨线程之间共享不可变数据,相较于传统的线程局部变量(Thread-Local Variables),它更适用于大量虚拟线程(Virtual Threads)的场景。
主要变更
在JDK 23中,Scoped Values API 的重新预览引入了一个重要变更:ScopedValue.callWhere 方法的操作参数现在是一个函数式接口。这一变更使得Java编译器能够推断是否可能抛出受检异常。因此,ScopedValue.getWhere 方法不再需要,已被移除。这不仅简化了代码,还提升了在频繁数据共享场景下的性能。
Scoped Values 的优势
Scoped Values 使方法能够与被调用者和子线程共享不可变数据,相较于线程局部变量,它更易于管理和推理数据流。其空间和时间成本更低,尤其是在与虚拟线程(JEP 444)和结构化并发(JEP 480)结合使用时。
线程局部变量的局限性
线程局部变量自 Java 1.2 引入,是传统的数据共享方式,但也存在一些显著缺点:
- 无约束的易变性:任何代码都可以随时修改线程局部变量的值,可能导致不一致性。
- 无限的生命周期:值可能比实际需要的时间更长,如果开发者忘记调用
remove方法,可能导致内存泄漏。 - 线程间继承的高开销:每个子线程必须为父线程中写入的每个线程局部变量分配存储空间,显著影响性能。
Scoped Values 通过确保数据不可变且仅在定义的作用域内可访问,解决了上述问题,从而提升了安全性和性能。
示例对比
以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);
}
}使用Scoped Values的实现:
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);
}
}总结
Scoped Values API 显著改善了 Java 中跨方法和线程共享数据的方式,推动了更好的编码实践并提升了应用性能。它特别适用于现代并发模型,尤其是在虚拟线程的背景下,成为开发高并发应用的重要工具。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。