ScopedValue 为什么被说成比 ThreadLocal 更适合传递上下文?这篇用 JDK 27(ScopedValue 已正式)逐项验证:范围、不可变、线程池泄漏、线程间传递,并如实检验「更省内存」这个说法(虚拟线程的基本行为见前面的篇目)。
绑定之前:USER.isBound() = false
绑定之前 USER.get() → NoSuchElementException
绑定范围内:USER.get() = ann,isBound = true
嵌套重新绑定:内层 USER.get() = bob
内层结束后外层 USER.get() = ann(自动恢复)
orElse:USER.orElse("默认") = ann
范围结束后:USER.isBound() = false
call 的返回值:carol
范围里抛异常传出来之后:USER.isBound() = false(异常也会解除绑定)
ScopedValue 只有 get / isBound / orElse / orElseThrow,没有 set 方法:[]单线程池里,任务 1 对 ThreadLocal 调了 set 但没有 remove;任务 2 读到:上一个任务设置的值(泄漏到下一个任务) 任务 1 用 ScopedValue 绑定;任务 2 读到:(未绑定)(没有泄漏)
main 里设置了 ThreadLocal、InheritableThreadLocal,并在 ScopedValue 绑定范围内启动新线程:
平台线程里读到:TL=null,InheritableTL=itl-main,ScopedValue=(未绑定)
虚拟线程里读到:TL=null,InheritableTL=itl-main,ScopedValue=(未绑定)
(ScopedValue 不会自动传给用 new Thread 启动的线程;要传,需要在新线程里重新绑定,或用结构化并发(preview,本篇没有验证))100000 个同时存活的虚拟线程(每个都阻塞在同一个 latch 上,所有线程用的都是同一个共享的 1 KB 数组),堆增加:什么都不绑定 99 MB;每个线程 ThreadLocal.set(共享对象) 97 MB;每个线程 ScopedValue.where(共享对象).run 95 MB(各 1047 / 1021 / 1001 字节每线程)