Random.nextInt仅支持单参数上界,生成[min, max]需用nextInt(max-min+1)+min;ThreadLocalRandom原生支持双参数且线程安全;用户输入需校验边界;业务还需考虑去重、加权等语义约束。

Random.nextInt 不能直接生成指定上下边界的随机数
Java 的 Random.nextInt(int bound) 只接受一个上界(exclusive),不支持直接传入 min 和 max。试图写成 random.nextInt(10, 20) 会编译失败——这个重载方法根本不存在。
常见错误是误以为它类似 Python 的 random.randint(min, max),结果出现 cannot resolve method nextInt(int, int) 报错。
- 正确做法是用
nextInt(max - min + 1) + min - 注意:
bound必须为正整数,所以max >= min是前提,否则会抛出IllegalArgumentException - 如果中奖数字范围是 [1, 100](含两端),应写成
random.nextInt(100) + 1,不是random.nextInt(100)(那是 [0,99])
使用 ThreadLocalRandom 替代 Random 更适合多线程抽奖场景
如果中奖逻辑部署在 Web 服务中(比如每秒数百次抽奖请求),用共享的 Random 实例可能引发竞争,而 ThreadLocalRandom 是线程安全且无锁的,性能更好。
- 获取实例:直接调用
ThreadLocalRandom.current(),不要缓存或复用它 - 生成 [min, max] 区间整数:
ThreadLocalRandom.current().nextInt(min, max + 1)—— 注意这里nextInt(int origin, int bound)是 inclusive-exclusive 形式,origin包含,bound不包含 - 对比:
Random需手动计算偏移,ThreadLocalRandom原生支持双参数,更不易出错
边界值必须校验,尤其当 min/max 来自用户输入或配置
中奖数字范围若来自 HTTP 参数、数据库配置或环境变量,必须做合法性检查,否则可能触发异常或逻辑漏洞。
- 检查
min ,且两者均为非负整数(如中奖号码通常 ≥ 1) - 防止整数溢出:例如
max - min很大时,nextInt(max - min + 1)中的加法可能溢出为负数,导致 bound ≤ 0 —— 这会立即抛出异常 - 建议封装工具方法:
public static int nextIntInRange(Random r, int min, int max) { if (min > max) throw new IllegalArgumentException("min > max: " + min + ", " + max); return r.nextInt(max - min + 1) + min; }
抽奖不是纯随机就够了,还要考虑业务语义
生成一个“随机中奖数字”听起来简单,但实际中常需满足额外约束:比如不能重复中奖、需按概率加权、或需与历史记录去重。这时候 nextInt 只是起点。
- 若要求“本次中奖号不能和上一期相同”,得额外维护状态,不能只靠随机函数
- 若要实现“一等奖概率 1%,二等奖 99%”,就不能用均匀分布的
nextInt直接映射,而应结合nextDouble()做区间划分 - 测试时别忘了固定种子:
new Random(42),否则难以复现“为什么这次抽到 7,上次是 13”这类问题
真正容易被忽略的是:随机性本身不等于公平性,也不等于可用性。生成数字只是第一步,后续怎么用、怎么验、怎么容错,才是中奖逻辑稳不稳的关键。










