java.util.Random 是線性同餘生成器(LCG),本質是確定性演算法。構造函數接受 long seed,若未指定則以 System.nanoTime() 混合哈希作為種子。核心邏輯:
// 簡化版 next(int bits)
seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
return (int)(seed >>> (48 - bits));
每次調用 nextInt() 都會更新種子,下一次輸出基於新種子。因此:
// 代碼 A:循環內 new Random(10)
for (int i=0; i<10; i++) {
Random r = new Random(10);
System.out.print(r.nextInt(10) + " ");
}
// 輸出:10 個相同數字(每次重置種子,取序列第一個值)
// 代碼 B:循環外 new Random(10)
Random r = new Random(10);
for (int i=0; i<10; i++) {
System.out.print(r.nextInt(10) + " ");
}
// 輸出:10 個不同數字(序列依次推進)
// 再次運行主程序:輸出序列與上一次完全相同
Math.random() 內部持有單例 Random,首次調用時以當前時間種子初始化,故多次循環調用產生不同序列,但進程重啟後序列仍可重現(若種子相同)。
| 類別 | 線程安全 | 密碼學安全 | 適用場景 |
|---|---|---|---|
Random | 是(CAS 更新種子) | 否 | 模擬、測試、遊戲邏輯 |
ThreadLocalRandom | 是(線程隔離) | 否 | 高併發非安全隨機 |
SecureRandom | 是 | 是 | Token、Key、Session ID、加密 |
SplittableRandom | 否(非線程安全) | 否 | Fork/Join 平行流、可分割流 |
Random 爭搶 CAS 退避:改用 ThreadLocalRandom.current().nextInt() 消除共享種子競爭SecureRandomnew Random(12345L) 確保測試數據確定性ThreadLocalRandom.current()SecureRandom.getInstanceStrong()
3. 並行流/分治演算法:SplittableRandom
4. 單元測試固定數據:new Random(fixedSeed)
5. 避免 new Random() 在循環中重複創建(種子可能相同導致輸出重複)
理解偽隨機本質,才能在正確場景選擇正確工具,避免「以為隨機實則可預測」的安全事故與效能瓶頸。