Java jdk21- 446 Scoped Values 作用域值
·
一、作用域值定义
作用域值可以在同一个线程的多个方法之间方便地共享数据。相对于传统的ThreadLocal来说,更安全,同时权限控制可以精确到方法级别。
二、核心特性
1. 不可变性:
ScopedValues的值一旦设置,就不能更改。这确保了数据的安全性和一致性。
2.作用域限制:
ScopedValues的生命周期严格限制在其定义的作用域内,超出作用域后无法访问。
3.支持虚拟线程:
ScopedValues与虚拟线程无缝集成,适合高并发场景。
4.无副作用:
由于ScopedValues是不可变的,它们不会引入传统线程局部变量可能带来的副作用。
三、ThreadLocal 与Scoped Values 的对比

public class Main1 {
private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("张三");
run_1();
//可以获取
System.out.println("main:" + threadLocal.get());
}
private static void run_1() {
System.out.println("run_1:" + threadLocal.get());
// 问题:必须手动清理,容易忘记清理,导致内存泄露
threadLocal.remove();
run_2();
}
private static void run_2() {
System.out.println("run_2:" + threadLocal.get());
}
}
import java.lang.ScopedValue;
public class Main {
//值封装在ScopedValue中
private static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();
public static void main(String[] args) {
//在作用域内获取当前用户
ScopedValue.runWhere(CURRENT_USER, "李四", Main::run_1);
//不在作用域内,不能获取数据
//发生异常:Exception in thread "main" java.util.NoSuchElementException
// System.out.println("main:" + CURRENT_USER.get());
}
public static void run_1(){
System.out.println("run_1:" + CURRENT_USER.get());
ScopedValue.runWhere(CURRENT_USER, "张三", Main::run_2);
}
public static void run_2(){
System.out.println("run_2:" + CURRENT_USER.get());
}
}


四、适用场景
-
虚拟线程中的上下文传递
如用户会话、请求 ID 等,确保每个虚拟线程独立访问数据。 -
替代 ThreadLocal
避免内存泄漏和手动清理,例如在 Web 框架中传递请求级数据。 -
高并发系统
在分布式系统中传递事务 ID 或跟踪 ID,简化日志上下文管理。
案例1:日志上下文管理
public class Test2 {
// 定义一个静态最终的 ScopedValue 对象
private static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();
public static void main(String[] args) {
System.out.println("=== Scoped Values ===");
// 场景1:管理员操作
ScopedValue.where(CURRENT_USER, "管理员Alice")
.run(() -> performSecureOperation());
// 场景2:普通用户操作
ScopedValue.where(CURRENT_USER, "普通用户Bob")
.run(() -> performSecureOperation());
System.out.println("=== 结束 ===");
}
private static void performSecureOperation() {
// 在作用域内获取当前用户
String user = CURRENT_USER.get();
System.out.println("当前执行用户: " + user);
// 调用深层方法,无需传递用户参数
logOperation();
validateAccess();
}
private static void logOperation() {
// 任何被调用的方法都可以访问作用域值
String user = CURRENT_USER.get();
System.out.println("[" + user + "] 执行了安全操作");
}
private static void validateAccess() {
String user = CURRENT_USER.get();
if (user.startsWith("管理员")) {
System.out.println("权限验证通过: " + user + " 拥有完全访问权限");
} else {
System.out.println("权限验证通过: " + user + " 拥有基础访问权限");
}
}
}

案例2:虚拟线程中的上下文传递
package org.hlx;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class MyScopeValue3 {
private static final ScopedValue USER_SESSION = ScopedValue.newInstance();
private static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();
public static void main(String[] args) {
//虚拟线程中的使用示例
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 提交多个任务,每个任务都有自己的作用域
for (int i = 0; i < 5; i++) {
final int taskId = i;
executor.submit(() -> {
UserSession taskSession = new UserSession(
"task-user-" + taskId,
"任务用户" + taskId,
"user"
);
ScopedValue.where(USER_SESSION, taskSession)
.where(REQUEST_ID, "task-req-" + taskId)
.run(() -> {
System.out.println("虚拟线程 " + Thread.currentThread() +
" 处理请求 " + REQUEST_ID.get() +
" 处理用户: " + ((UserSession)USER_SESSION.get()).getUsername());
});
});
}
// 等待所有任务完成
executor.shutdown();
executor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println();
}
package org.hlx;
/*
* 用户会话类
*/
public class UserSession {
private String userId;
private String username;
private String role;
public UserSession(String userId, String username, String role) {
this.userId = userId;
this.username = username;
this.role = role;
}
public String getUserId() {
return userId;
}
public String getUsername() {
return username;
}
public String getRole() {
return role;
}
}

总之,Java ScopedValue适用于高并发、虚拟线程场景,提供安全、高效的作用域值管理,是 ThreadLocal 的现代替代方案。
更多推荐


所有评论(0)