threadlocalrandom 通过为每个线程维护独立的随机种子(threadlocalrandomseed)和探针值(threadlocalrandomprobe),避免了多线程争用共享变量的开销;其不依赖 atomicinteger,而是利用 thread 类私有字段配合 unsafe 直接操作,实现无锁、高效、线程安全的随机数生成。

ThreadLocalRandom 并不依赖全局原子变量,而是为每个线程维护独立的随机种子(threadLocalRandomSeed)和探针值(threadLocalRandomProbe),从根本上避免了多线程争用同一变量的开销。
ThreadLocalRandom 为什么不用 AtomicInteger
传统 Random 使用 AtomicLong seed 作为共享种子,每次生成随机数都要执行 CAS 更新,高并发下容易因失败重试导致性能下降。ThreadLocalRandom 则放弃共享状态,让每个线程持有自己的种子副本——这个种子就存放在当前线程对象(Thread)的私有字段中:
-
threadLocalRandomSeed:long 类型,记录该线程专属的当前随机种子 -
threadLocalRandomProbe:int 类型,用于初始化时生成探针,也参与某些散列逻辑 - 这两个字段在 Thread 类中被声明为
private static final的 Unsafe 偏移量访问目标,不对外暴露,也不参与继承或共享
种子如何初始化与更新
首次调用 current() 时,ThreadLocalRandom 会检查当前线程的 threadLocalRandomSeed 是否已初始化。若未初始化,则通过以下方式安全设置:
- 读取当前线程的
threadLocalRandomProbe,若为 0 则先调用nextSecondarySeed()初始化探针 - 用系统纳秒时间、probe 值、线程 ID 等混合计算出初始种子,再通过 Unsafe 写入
threadLocalRandomSeed - 后续每次生成随机数(如
nextInt()),都直接读-修改-写本地种子,无需同步或 CAS
这种“读种子 → 计算新值 → 写回本地”的流程完全无竞争,指令级串行,效率接近普通 long 运算。
threadLocalRandomSeed 存在的意义不只是“隔离”
它不仅是线程本地副本,更是设计上对伪随机数生成器(PRNG)特性的尊重:一个合格的 PRNG 应具备状态连续性与确定性。多个线程共用一个种子会导致序列相互干扰,破坏统计均匀性;而各自维护独立种子,既保证了每个线程内随机流的高质量,又天然满足“线程间输出不可预测、互不相关”的要求。JDK 选择将种子下沉到 Thread 实例层面,而非用 ThreadLocal<long></long> 包装,是因为:
- 避免 ThreadLocal 的哈希表查找开销和内存泄漏风险
- 利用 JVM 对 Thread 字段的优化(如字段重排序、缓存行对齐)提升访问速度
- 与 FJP(ForkJoinPool)深度集成,子任务继承父线程种子并扰动,兼顾局部性与独立性
不复杂但容易忽略的关键点
ThreadLocalRandom 的高效不是靠算法多先进,而是把“随机数生成必须有状态”这个事实,坦诚地交给线程自身承载。它不试图在共享层做协调,而是承认并发的本质是“各干各的”。只要线程存在,种子就在;线程结束,字段随对象回收。没有注册、无需清理、不依赖 GC 特殊处理——一种克制而精准的并发设计。











