threadlocalrandom.current() 是并发场景下最安全高效的随机数获取方式,它为每个线程分配独立实例,避免cas竞争和伪共享;jdk 9+用@contended隔离字段,吞吐量可达new random()的5–8倍。

ThreadLocalRandom.current() 是并发场景下最安全的随机数获取方式
它不是线程安全的包装器,而是为每个线程分配独立的 Random 实例,天然规避了 java.util.Random 的 CAS 竞争和伪共享问题。别再用 new Random() 或静态 Random 实例做并发随机——那是在给 CPU 缓存行“添堵”。
为什么 ThreadLocalRandom 能规避伪共享
伪共享本质是多个线程频繁修改同一缓存行(64 字节)里的不同变量,导致缓存一致性协议反复使其他核心的缓存副本失效。ThreadLocalRandom 的每个线程实例都持有独立的 seed 字段,且 JDK 9+ 已用 @Contended 注解隔离关键字段(如 probe、seeder),强制它们落在不同缓存行上。
-
ThreadLocalRandom不共享状态,没有跨线程写冲突 - 它的
nextLong()、nextInt(int bound)等方法全程只读写本线程的私有字段 - 对比
java.util.Random:其seed是AtomicLong,每次调用next()都触发compareAndSet,引发缓存行无效化风暴
正确用法:只调用 current() + 具体生成方法
不要保存 ThreadLocalRandom 实例引用,更不要在构造器里缓存它——线程切换后该实例就“过期”了。每次需要随机数时,直接调用静态方法。
- ✅ 正确:
int x = ThreadLocalRandom.current().nextInt(100); - ❌ 错误:
private final ThreadLocalRandom rnd = ThreadLocalRandom.current();(线程池中会复用线程,但rnd实例不会自动更新) - ⚠️ 注意:
ThreadLocalRandom不支持设置自定义 seed;若需可重现的序列,请改用线程局部的Random实例并手动管理 seed - ⚠️ 注意:
current()在非 ForkJoinPool 线程或未初始化的线程中首次调用会有微小开销(初始化 probe 值),但仅一次
性能差异在高并发下非常明显
在 32 核机器上压测每秒百万级随机数生成:ThreadLocalRandom 吞吐量通常是 new Random() 的 5–8 倍,是静态 Random 实例的 10 倍以上。差距主要来自避免了 CAS 自旋和缓存行颠簸。
立即学习“Java免费学习笔记(深入)”;
- 使用 JMH 测量时,务必开启
-XX:-RestrictContended(JDK 8u20+ 默认关闭@Contended) - 如果看到
java.util.concurrent.ThreadLocalRandom$TLRandom出现在火焰图热点里,说明你可能误用了它(比如把它当单例注入 Spring) - Spring Boot 项目里,别在
@Component中 autowireThreadLocalRandom——它不是 Spring 管理的 bean,也不该是
ThreadLocalRandom 的设计,就是从源头切断这个链路。只要记住“每次要的时候才 current()”,就踩不到坑。










