导读:本期聚焦于小伙伴创作的《什么是ScopedValue的不可变性?相比ThreadLocal在虚拟线程中有哪些性能优势》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《什么是ScopedValue的不可变性?相比ThreadLocal在虚拟线程中有哪些性能优势》有用,将其分享出去将是对创作者最好的鼓励。

ScopedValue是Java并发包中引入的新特性,主要面向虚拟线程场景设计,用于在线程执行范围内传递上下文信息,它的不可变性设计和ThreadLocal有本质区别,在虚拟线程大量创建的场景下能带来明显的性能提升。

什么是ScopedValue的不可变性?相比ThreadLocal在虚拟线程中有哪些性能优势

ScopedValue的不可变性含义

ScopedValue的不可变性指的是一旦ScopedValue被绑定了值,在整个绑定的作用域内这个值无法被修改,也不能被重新绑定,直到作用域结束才会自动解除绑定。这和ThreadLocal可以随时调用set方法修改存储值的特性完全不同。

ScopedValue的绑定操作是通过ScopedValue.where方法完成的,绑定之后只能在当前作用域内读取,不能修改。下面是一个简单的ScopedValue使用示例:

import java.lang.ScopedValue;

public class ScopedValueDemo {
    // 定义一个ScopedValue实例
    private static final ScopedValue<String> USER_NAME = ScopedValue.newInstance();

    public static void main(String[] args) {
        // 绑定值到ScopedValue,作用域为run方法内的代码块
        ScopedValue.where(USER_NAME, "test_user")
                .run(() -> {
                    // 在作用域内读取绑定的值
                    String name = USER_NAME.get();
                    System.out.println("当前用户名称:" + name);
                    // 尝试修改会编译报错,ScopedValue没有set方法
                    // USER_NAME.set("new_user"); 这行代码无法编译通过
                });
        // 作用域外无法读取到绑定的值,会抛出异常
        try {
            USER_NAME.get();
        } catch (NoSuchElementException e) {
            System.out.println("作用域外无法获取ScopedValue的值");
        }
    }
}

ThreadLocal在虚拟线程中的问题

ThreadLocal的设计是基于线程实例存储数据的,每个线程都有自己独立的ThreadLocalMap,存储对应ThreadLocal实例的值。在传统的平台线程场景下,线程数量有限,ThreadLocal的开销可以忽略不计。但在虚拟线程场景下,虚拟线程是轻量级的,可能会被大量创建和销毁,ThreadLocal会带来两个问题:

  • 内存开销大:每个虚拟线程都会维护自己的ThreadLocalMap,大量虚拟线程会占用大量内存,而且ThreadLocal的值如果没有及时清理,还可能导致内存泄漏。
  • 绑定开销高:ThreadLocal的set和get操作需要操作线程本地的Map,虚拟线程的调度频繁,每次操作的开销会被放大。

ScopedValue相比ThreadLocal的性能优势

ScopedValue在虚拟线程中的性能优势主要来源于它的不可变性设计和作用域绑定机制,具体体现在以下几个方面:

1. 更低的内存占用

ScopedValue不需要每个虚拟线程维护独立的存储结构,它的绑定信息是和作用域关联的,作用域结束后自动清理,不会像ThreadLocal那样因为虚拟线程的创建销毁产生大量冗余的内存占用。下面是两者的内存占用对比:

对比项ThreadLocalScopedValue
存储结构归属每个线程独立维护ThreadLocalMap绑定信息关联作用域,不归属线程
大量虚拟线程场景内存占用高,每个虚拟线程都有独立的Map低,作用域结束自动回收
内存泄漏风险高,未及时remove可能导致泄漏无,作用域结束自动解除绑定

2. 更快的读写速度

ScopedValue的读取操作不需要像ThreadLocal那样查找线程本地的Map,它的绑定信息在作用域内是可直接访问的,读写开销更低。我们可以通过一个简单的性能测试对比两者的耗时:

import java.lang.ScopedValue;
import java.util.concurrent.ThreadLocalRandom;

public class PerformanceTest {
    private static final ThreadLocal<Integer> THREAD_LOCAL = ThreadLocal.withInitial(() -> 0);
    private static final ScopedValue<Integer> SCOPED_VALUE = ScopedValue.newInstance();

    public static void main(String[] args) {
        int loopCount = 1000000;
        // 测试ThreadLocal读写耗时
        long threadLocalStart = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            THREAD_LOCAL.set(ThreadLocalRandom.current().nextInt());
            int val = THREAD_LOCAL.get();
            THREAD_LOCAL.remove();
        }
        long threadLocalEnd = System.currentTimeMillis();
        System.out.println("ThreadLocal 100万次读写耗时:" + (threadLocalEnd - threadLocalStart) + "ms");

        // 测试ScopedValue读写耗时
        long scopedValueStart = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            int finalI = i;
            ScopedValue.where(SCOPED_VALUE, ThreadLocalRandom.current().nextInt())
                    .run(() -> {
                        int val = SCOPED_VALUE.get();
                    });
        }
        long scopedValueEnd = System.currentTimeMillis();
        System.out.println("ScopedValue 100万次读写耗时:" + (scopedValueEnd - scopedValueStart) + "ms");
    }
}

在虚拟线程大量创建的场景下,ScopedValue的读写耗时通常会比ThreadLocal低30%以上,因为省去了线程本地Map的查找和修改开销。

3. 更适配虚拟线程的调度模型

虚拟线程是挂载在平台线程上执行的,可能会发生频繁的挂载和卸载,ThreadLocal的存储是和虚拟线程绑定的,调度过程中需要维护这些绑定关系。而ScopedValue的绑定是和作用域绑定的,和虚拟线程的调度无关,不会因为虚拟线程的切换产生额外的开销。

使用场景建议

如果你的应用使用的是虚拟线程,并且需要在执行范围内传递上下文信息,且上下文的值在作用域内不需要修改,那么优先选择ScopedValue。如果是在传统的平台线程场景,或者需要随时修改上下文的值,那么ThreadLocal仍然是合适的选择。

注意:ScopedValue是Java 21中正式引入的特性,使用前需要确保JDK版本不低于21。

ScopedValueThreadLocal虚拟线程不可变性修改时间:2026-06-13 20:21:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。