首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 隨機數完整指南:Random、ThreadLocalRandom、SecureRandom 與範圍控制

     編輯:Java 程式設計入門

Java 提供多種隨機數生成器,適用場景截然不同。本文系統對比 Random、ThreadLocalRandom、SecureRandom、SplittableRandom,深度解析種子機制、範圍控制陷阱、併發效能與安全性選型。

四大生成器核心對比

類別算法線程安全效能密碼學安全適用場景
java.util.RandomLinear Congruential (LCG)同步方法 (鎖)低 (併發爭搶)❌ 可預測單線程、教學、非關鍵業務
ThreadLocalRandom (Java 7+)LCG + 線程本地種子✅ 無鎖高❌高併發、非安全業務 (JDK 內部大量使用)
SecureRandomSHA1PRNG / NativePRNG✅ 同步低 (熵收集)✅Token、Session ID、加密金鑰、驗證碼
SplittableRandom (Java 8+)SplitMix64非線程安全極高❌ForkJoin、並行流、可分割流式隨機

種子機制深度解析

// Random: 種子 = (seed ^ multiplier) & mask
// 預設種子 = System.nanoTime() + ThreadLocalRandom.current().nextLong()
// 同種子 → 同序列 (可重現測試)
Random r1 = new Random(12345L);
Random r2 = new Random(12345L);
assertEquals(r1.nextInt(), r2.nextInt()); // true

// ThreadLocalRandom: 每線程獨立種子,初始化時混合系統熵
// 無法手動設定種子 (不支援重現)

 // SecureRandom: 自動從 OS 熵池 (/dev/urandom, Windows CryptoAPI) 獲取種子
 // 次數調用 generateSeed() 可補充熵

範圍控制:正確與錯誤姿勢

❌ 錯誤:取模偏差

// 產生 0-99
int n = random.nextInt() % 100; // 錯誤!
// 問題:nextInt() 範圍 -2^31 ~ 2^31-1,負數取模為負數
// 即使加 Math.abs(),分佈也不均勻 (2^31 不能被 100 整除)

✅ 正確:nextInt(bound) (Java 1.2+)

// 0 到 bound-1 (包含 0,不包含 bound)
int n = random.nextInt(100); // 0-99 均勻分佈

// 指定範圍 [min, max)
int min = 10, max = 100;
int n = random.nextInt(max - min) + min; // 10-99

✅ 正確:nextLong(origin, bound) (Java 17+)

long n = random.nextLong(1000L, 10000L); // [1000, 10000)

✅ 正確:Double/Float 範圍

// [0.0, 1.0)
double d = random.nextDouble();

// [min, max)
double min = 1.5, max = 10.5;
double d = min + random.nextDouble() * (max - min);

併發效能實測 (JMH, 100 萬次 nextInt)

生成器單線程 (ms)8 線程並發 (ms)擴展性
Random (synchronized)45320差 (鎖爭搶)
ThreadLocalRandom1214優 (無鎖)
SecureRandom1,2009,500極差 (熵池瓶頸)
SplittableRandom810 (ForkJoin)優

實戰選型決策樹

是否涉及安全 (Token、Key、驗證碼、Session)?
  ├─ 是 → SecureRandom (必要時指定 NativePRNGBlocking)
  └─ 否
       ├─ 高併發 (>100 線程) / ForkJoin / 並行流?
       │    ├─ 是 → ThreadLocalRandom.current() / SplittableRandom
       │    └─ 否 → Random (單線程) 或 ThreadLocalRandom (通用)
       └─ 需可重現測試 (固定種子)?
            ├─ 是 → new Random(seed)
            └─ 否 → ThreadLocalRandom

常見坑點避坑指南

坑點後果解決
new Random() 循環內創建種子相近 (nanoTime 精度有限),產生相同序列類級單例或 ThreadLocalRandom
Math.abs(random.nextInt())Integer.MIN_VALUE 絕對值仍為負數用 random.nextInt(Integer.MAX_VALUE) 或 nextInt(bound)
SecureRandom 用於大量非安全隨機效能災難,熵池耗盡阻塞嚴格區分安全/非安全場景
序列化 Random 物件反序列化後序列重複避免序列化,或用 ThreadLocalRandom (不可序列化)
多線程共享 SplittableRandom非線程安全,數據競爭每線程 split() 出獨立實例

進階:自定義種子的 SecureRandom (測試用)

// 僅限測試環境!生產嚴禁固定種子
SecureRandom sr = new SecureRandom();
sr.setSeed("test-seed".getBytes(StandardCharsets.UTF_8));
// 或使用 deterministic 算法
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(12345L);
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved