前言
ScopedValue是jdk21引入新属性,用来代替ThreadLocal的线程传值,ScopedValue目前处于预览状态,将支持在线程内和线程间共享不可变数据。它们优于线程局部变量,尤其是在使用大量虚拟线程时
jdk21使用虚拟线程
jdk21在使用虚拟线程时,需要开启预览状态,以下是maven开启预览状态
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<compilerArg>--enable-preview</compilerArg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
或者在ide启动时,加入参数的预览
ScopedValue使用
where方法
where方法的参数为:
public static <T> Carrier where(ScopedValue<T> key, T value)
value是要获取的值,把当前值绑定在当前线程中 示例为:
public class ScopedValue1Demo {
private static ScopedValue<String> stringScopedValue = ScopedValue.newInstance();
public static void main(String[] args) {
ScopedValue.where(stringScopedValue, say()).run(() -> {
String result = stringScopedValue.get();
System.out.println(result);
hello();
});
System.out.println(stringScopedValue.get());
}
public static String say() {
System.out.println("============say()方法");
return "aaa";
}
public static void hello() {
System.out.println(stringScopedValue.get());
}
}
最后在main方法获取参数会报异常
runWhere使用
runwhere的方法参数为:
public static <T> void runWhere(ScopedValue<T> key, T value, Runnable op)
示例为:
public class ScopedValueDemo {
private static ScopedValue<String> stringScopedValue = ScopedValue.newInstance();
public static void main(String[] args) {
ScopedValue.runWhere(stringScopedValue, "aaa", () -> {
System.out.println(stringScopedValue.get());
}
);
}
}
callWhere使用
public static <T, R> R callWhere(ScopedValue<T> key,
T value,
Callable<? extends R> op) throws Exception
示例为:
public class ScopedValue3Demo {
private static ScopedValue<String> stringScopedValue = ScopedValue.newInstance();
public static void main(String[] args) throws Exception {
String result = ScopedValue.callWhere(stringScopedValue, say(), ()->{
System.out.println(12);
System.out.println(stringScopedValue.get());
return "aaa";
});
System.out.println(result);
}
public static String say() {
System.out.println("============say()方法");
return "aaa";
}
}
线程传值问题
import java.util.concurrent.ExecutionException;
import java.util.concurrent.StructuredTaskScope;
public class ScopedValue4Demo {
private static ScopedValue<String> stringScopedValue = ScopedValue.newInstance();
public static void main(String[] args) {
ScopedValue.runWhere(stringScopedValue, "aaaa", () -> {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
StructuredTaskScope.Subtask<String> user = scope.fork(() -> {
System.out.println("hello:" + stringScopedValue.get());
return "hello";
});
StructuredTaskScope.Subtask<Integer> order = scope.fork(() -> {
System.out.println("say():" + stringScopedValue.get());
return 12;
});
try {
scope.join().throwIfFailed();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
}
});
}
}
总结
ThreadLocal使用的时候,需要remove参数,但是ScopedValue在使用时,是不需要remove参数的,ScopedValue 具备 ThreadLocal 的核心特征,也就是每个线程只有一个值。与 ThreadLocal 不同的是,ScopedValue 是不可变的,并且有确定的作用域,但是同样的,ThreadLocal也能在线程中使用,这个看个人习惯