Java 25 ScopedValue - 作用域内安全访问的一种实现

Java 25 ScopedValue - 作用域内安全访问的一种实现

1、ScopedValue 简述

  • ScopedValue基本用法:定义一个ScopedValue,使用ScopedValue.where()方法创建一个作用域,在该作用域内可以安全地访问ScopedValue的值,当执行离开作用域时,值会自动解除绑定。

2、ScopedValue 优势

  • 相比ThreadLocal的优势在于:
  • 更清晰的变量生命周期管理
  • 减少了内存泄漏的风险
  • 更好的类型安全性
  • 更适合现代并发编程模型

3.1、基本用法示例

java 复制代码
public class ScopedValueExample {

    // 定义一个 ScopedValue String 类型
    private static final ScopedValue<String> USER_NAME = ScopedValue.newInstance();

    // 定义一个 ScopedValue Map 类型
    private static final ScopedValue<Map<String, Integer>> USER_MAP = ScopedValue.newInstance();

    public static void main(String[] args) {

        // 在作用域内设置值 String 类型
        ScopedValue.where(USER_NAME, "就不告诉你")
                .run(() -> {
                    // 在这个作用域内可以访问USER_NAME
                    System.out.println("用户名: " + USER_NAME.get());
                    // 可以调用其他方法,值会自动传递
                    processData();
                });


        // 在作用域内设置值 Map 类型
        Map<String, Integer> userMap = new HashMap<>();
        userMap.put("小明", 28);
        userMap.put("小黑", 25);
        ScopedValue.where(USER_MAP, userMap)
                .run(() -> {
                    // 在这个作用域内可以访问 USER_MAP 信息
                    System.out.println("小明年龄: " + userMap.get("小明"));
                    // 可以调用其他方法,值会自动传递
                    processMapData();
                });


        // 作用域外无法访问
//         System.out.println(USER_NAME.get()); // 会抛出IllegalStateException
         System.out.println(USER_MAP.get().get("小明")); // 会抛出IllegalStateException
    }

    private static void processMapData() {
        // 可以在子方法中访问 ScopedValue
        System.out.println("子方法中获取小黑年龄: " + USER_MAP.get().get("小黑"));

    }

    private static void processData() {
        // 可以在子方法中访问 ScopedValue
        System.out.println("子方法中获取用户名: " + USER_NAME.get());
    }

}

3.2 优势‌

  • 无需手动 remove(),作用域结束自动清理。
    与虚拟线程兼容,支持结构化并发。

4.1 线程池场景示例

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExample {

    static final ScopedValue<Integer> TASK_ID = ScopedValue.newInstance();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        // ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {

                // 作用域内自动管理生命周期
                ScopedValue.where(TASK_ID, taskId)
                        .run(() -> {
                            System.out.println("Task " + TASK_ID.get() + " running");
                            // 业务逻辑
                            // 可以调用其他方法,值会自动传递
                            doSomethings();
                        });
            });
        }
        executor.shutdown();

        //  Executors.newVirtualThreadPerTaskExecutor(); 执行时需添加,目的是为了等待线程执行完成
        // executor.awaitTermination(1, TimeUnit.MINUTES);

    }

    private static void doSomethings() {
        System.err.println(TASK_ID.get() + " doSomethings");
    }
}

4.2 优势‌

  • 避免线程池复用导致的数据串扰问题。
    作用域结束自动清理,无需显式 remove()

5.1 结构化并发示例

java 复制代码
import java.util.concurrent.*;
import java.time.Duration;

public class ScopedConcurrencyExample {
    
    // 定义业务上下文变量(相当于动态作用域变量)
    private static final ScopedValue<String> USER_ID = ScopedValue.newInstance();

    private static final ScopedValue<Duration> REQUEST_TIMEOUT = ScopedValue.newInstance();

    public static void main(String[] args) {

        final long startTime = System.currentTimeMillis();

        // 绑定上下文变量(会在所有子任务中自动继承)
        ScopedValue.where(USER_ID, "usr-20260106")
                  .where(REQUEST_TIMEOUT, Duration.ofSeconds(3))
                  .run(() -> processOrder(startTime));
    }

    private static void processOrder(long requestStartTime) {

        try (var scope = StructuredTaskScope.open()) {
            // 在相同作用域中启动并发任务
            StructuredTaskScope.Subtask<String> fetchInventory = scope.fork(() -> getInventory());
            StructuredTaskScope.Subtask<Integer> calcPayment = scope.fork(() -> calculatePayment(requestStartTime));

            // 模拟系统错误
            // scope.close();
            StructuredTaskScope.Subtask<String> genInvoice = scope.fork(() -> generateInvoice());

            // 等待所有任务完成
            scope.join();

            // 任务完成后的结果处理
            System.out.println(
                "订单处理结果:\n" +
                "用户: " + USER_ID.get() + "\n" +
                "库存状态: " + fetchInventory.get() + "\n" +
                "支付金额: $" + (calcPayment.get() / 100.0) + "\n" +
                "发票: " + genInvoice.get().replace("\n", "\n       ")
            );
            
        } catch (InterruptedException e) {
            System.err.println("订单处理异常: " + e.getMessage());
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            System.err.println("系统错误: " + e.getMessage());
        }
    }

    private static String getInventory() {
        System.out.println("获取库存 (用户: " + USER_ID.get() + ")");
        simulateWork(800);
        return "SKU-3456 库存充足";
    }

    private static Integer calculatePayment(long start) {

        Duration remaining = REQUEST_TIMEOUT.get().minusMillis(System.currentTimeMillis() - start);
        if (remaining.isNegative()) {
            throw new RuntimeException("支付计算超时");
        }

        System.out.println("计算支付 (剩余时间: " + remaining.toMillis() + "ms)");
        simulateWork(1200);
        return 4599;
    }

    private static String generateInvoice() {

        System.out.println("生成发票 (用户: " + USER_ID.get() + ")");
        simulateWork(1500);
        return 
            "发票编号: INV-" + USER_ID.get() + "-20260106\n" +
            "---------------------------------------\n" +
            "项目: 结构化并发服务包\n" +
            "金额: 4599.00";
    }

    private static void simulateWork(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("任务中断");
        }
    }
}

5.2 优势‌

  • 与虚拟线程天然兼容,支持嵌套作用域。
    子任务自动继承父作用域的值,无需手动传递参数。

6.1 高级特性-条件绑定与错误处理

java 复制代码
import java.lang.ScopedValue;

public class AdvancedFeatures {
    static final ScopedValue<String> MODE = ScopedValue.newInstance();

    public static void main(String[] args) {
        // 条件绑定
        ScopedValue.where(MODE, "production")
                .run(() -> {
                    if ("production".equals(MODE.get())) {
                        System.out.println("Running in production mode");
                    } else {
                        System.out.println("Running in test mode");
                    }
                });

        // 错误处理
        try {
            ScopedValue.where(MODE, "test")
                    .run(() -> {
                        throw new RuntimeException("Simulated error");
                    });
        } catch (RuntimeException e) {
            System.out.println("Caught exception: " + e.getMessage());
        }
    }
}

6.2 优势‌

  • 支持条件绑定,根据值执行不同逻辑。
    异常处理时自动清理作用域,无需额外操作。

7. 总结

  • copedValue 通过作用域管理机制,解决了 ThreadLocal 的内存泄漏和数据串扰问题,尤其适用于虚拟线程和结构化并发场景。其自动清理特性显著简化了并发编程,提升了代码安全性和可维护性。

安装包路径

Open JDK 25:https://jdk.java.net/25/

相关推荐
2401_87690752几秒前
USB TYPE-C 公头连接器设计规范总结:提升可靠性、降本增效的关键指南
c语言·开发语言·设计规范
额呃呃5 分钟前
std::allocator<T>::destroy
开发语言
不知疲倦的仄仄6 分钟前
第二天:深入理解 Selector:单线程高效管理多个 Channel
java·nio
期待のcode10 分钟前
Java虚拟机栈
java·开发语言·jvm
珂朵莉MM10 分钟前
全球校园人工智能算法精英大赛-产业命题赛-算法巅峰赛 2025年度画像
java·人工智能·算法·机器人
芒克芒克11 分钟前
本地部署SpringBoot项目
java·spring boot·spring
cute_ming12 分钟前
关于基于nodeMap重构DOM的最佳实践
java·javascript·重构
sww_102619 分钟前
Netty原理分析
java·网络
小突突突37 分钟前
Spring框架中的单例bean是线程安全的吗?
java·后端·spring
iso少年41 分钟前
Go 语言并发编程核心与用法
开发语言·后端·golang