threadlocalrandom 比 random 快,因其 seed 存于线程私有 threadlocal 中,避免 cas 竞争与缓存行失效;而 random 使用全局 atomiclong,多线程下自旋重试导致性能下降。

ThreadLocalRandom 为什么比 Random 快?关键在 seed 存哪
因为 ThreadLocalRandom 的种子(seed)存在每个线程自己的 ThreadLocal 里,不共享;而 Random 的 seed 是一个全局的 AtomicLong,所有线程抢着改它。
多线程调用 nextInt() 时:
– Random 每次都要 CAS 更新同一个原子变量,失败就重试 → 自旋、缓存行失效(false sharing)、CPU 白耗
– ThreadLocalRandom 直接读写本线程私有 seed → 零竞争、无锁、L1 缓存命中率高
- 实测:100 线程并发 10 万次
nextInt(),ThreadLocalRandom通常快 3–8 倍 - 不是“算法更高级”,而是“根本不打架”——底层仍是线性同余法(LCG),和
Random一样 - seed 初始化延迟到首次调用
ThreadLocalRandom.current(),靠System.nanoTime()+ 线程 ID 衍生,不依赖类加载时机
别在 static 块或构造器里调用 ThreadLocalRandom.current()
这是最常踩的坑:类刚加载、线程还没真正“活”起来时,current() 可能返回 null 或直接抛 NullPointerException。
- 错误写法:
static final int DEFAULT_ID = ThreadLocalRandom.current().nextInt(1000);
- 正确写法:只在业务逻辑中、线程已就绪后调用,比如 Controller 方法、Runnable.run()、CompletableFuture 异步回调里
- 禁止缓存
ThreadLocalRandom.current()返回值跨方法传参——它绑定当前线程,换线程就失效
ThreadLocalRandom 不支持 setSeed(),但你真需要它吗?
它压根没提供 setSeed(long),调用就抛 UnsupportedOperationException。这不是缺陷,是设计取舍。
- 适合场景:服务端生成请求 ID、采样开关、负载均衡选节点——只要随机、不要可重现
- 不适合场景:单元测试、游戏关卡种子、算法验证——这些必须用
new Random(12345L)固定 seed - 想并行又想要可重现?别硬套
ThreadLocalRandom。老实用多个Random实例,seed 按线程 ID 偏移(如seedBase + threadId),但得自己分片管理
API 差异小但致命:别指望 nextGaussian() 或自定义分布
ThreadLocalRandom 的公开方法只有 nextInt()、nextLong()、nextDouble() 和带 bound 的重载,再没有了。
- 没有
nextGaussian()—— 正态分布得自己用 Box-Muller 或 Marsaglia 转换 - 没有
ints()/longs()的无限流(Random.ints()是无限的,ThreadLocalRandom.ints()必须指定 size 或 bound) - 并行流推荐写法:
ThreadLocalRandom.current().ints(0, 100).limit(1000).parallel().forEach(...)
,不是new Random().nextInt()塞进map
性能优势不是白给的,换来的就是 API 精简和不可控 seed——用之前先问一句:我到底要的是“快”,还是“可控”。










