多线程环境下应优先使用ThreadLocalRandom而非Random,因其无锁设计避免CAS竞争、吞吐量高;需通过current()获取实例,不支持setSeed,方法签名与Random一致但bound必须大于0。

多线程环境下直接用 Random 会竞争同一把锁,性能差;ThreadLocalRandom 是专为多线程设计的无锁随机数生成器,应优先选用。
什么时候该用 ThreadLocalRandom 而不是 Random
当代码运行在多线程中(比如 Web 应用、并行流、定时任务),且每个线程需要独立生成随机数时,ThreadLocalRandom 是更优选择。它避免了 Random 内部 AtomicLong 的 CAS 竞争,吞吐量高、延迟低。
- Web 请求中生成订单号片段、验证码、随机盐值 → 用
ThreadLocalRandom.current() - 使用
parallelStream()处理数据并随机采样 → 每个 fork 线程应调用自己的ThreadLocalRandom - 全局单例的
Random实例被多个线程共用 → 实际上是性能瓶颈,应替换 - 仅在单线程脚本或单元测试中简单生成几个数 →
Random仍可用,但没必要
ThreadLocalRandom 的正确初始化和常用方法
ThreadLocalRandom 不能通过 new 构造,必须调用静态方法 current() 获取当前线程专属实例。它的方法签名和 Random 高度一致,但去掉了所有 setSeed() 相关操作 —— 它不支持手动设种子,也不需要。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
ThreadLocalRandom random = ThreadLocalRandom.current(); int i = random.nextInt(10); // [0, 10) long l = random.nextLong(100L); // [0, 100) double d = random.nextDouble(0.5, 1.5); // [0.5, 1.5) boolean b = random.nextBoolean(); // true/false 各 50%
-
nextInt(int bound)和nextLong(long bound)的bound必须 > 0,否则抛IllegalArgumentException - 区间方法如
nextDouble(double origin, double bound)要求origin ,否则行为未定义(JDK 17+ 抛异常) - 不要缓存
ThreadLocalRandom.current()的返回值跨线程传递 —— 它只对当前线程有效
Random 在并发场景下的典型问题
直接共享一个 Random 实例(例如 static final Random RND = new Random();)会导致大量线程在 next(int) 内部争抢 seed 的 compareAndSet,表现为 CPU 使用率偏高、吞吐下降,尤其在高并发短耗时随机操作中明显。
static final Random BAD_SHARED_RANDOM = new Random(); // 多个线程同时调用,会卡在这里 int x = BAD_SHARED_RANDOM.nextInt(100); // 内部 synchronized + CAS 竞争
- 错误做法:把
Random声明为static并在工具类中复用 - 错误做法:在 Spring Bean 中注入单例
Random用于多请求场景 - 正确替代:改用
ThreadLocalRandom.current().nextInt(...),零额外对象分配 - 如果真需要可重现的随机序列(如测试、模拟),才用
new Random(seed),且确保每个线程有自己的实例
真正容易被忽略的是:很多团队沿用旧代码里的 static Random,没意识到它在压测时已成为瓶颈;而 ThreadLocalRandom 的 API 几乎完全兼容,替换成本极低,但效果立竿见影。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南









