公平随机抽奖的核心是“不重复”和“可验证”:用Fisher-Yates洗牌(Collections.shuffle)实现高效无放回抽取;高并发时借助Redis的SPOP或Lua保证原子性;通过业务ID生成固定seed实现可复现与审计。
关键不是“随机”,而是“不重复”和“可验证”。Java自带的Random或ThreadLocalRandom能生成随机数,但抽奖系统真正要解决的是:从N个用户中无放回地抽取M个中奖者,且过程可追溯、结果不可预测。
比反复生成随机索引再判重更高效、更公平。适用于名单确定、人数适中的场景(如内部活动抽奖):

优势:时间复杂度O(n),无冲突重试,结果完全随机且均匀分布。
当抽奖接口被高频调用(如|直播|抢红包),需防重复中奖和超发。纯内存List无法满足分布式一致性:
注意:Redis的SRANDMEMBER默认允许重复,如需严格无放回,优先用SPOP(会移除元素)或封装Lua脚本保证原子性。
运营常需复盘“某次抽奖为什么抽中A没抽中B”。这时不能依赖系统当前时间作为随机源:
这样既保持随机性,又满足合规与排查需求。