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

Java 隨機數生成全攻略:從 Math.random() 到 ThreadLocalRandom 的演進與避坑指南

     編輯:Java 相關知識

前言

「生成隨機數」看似簡單,實則暗藏效能陷阱與分布不均風險。本文梳理 Java 歷代隨機數 API 演進脈絡,對比 Math.random()、java.util.Random、ThreadLocalRandom 三代方案的優劣,並揭示 Math.round(Math.random()*n) 導致的分布偏差、Math.abs(rnd.nextInt())%n 的模運算陷阱,給出生產環境最佳實踐。

第一代:Math.random()——簡單但受限

double d = Math.random();           // [0.0, 1.0)
double d10 = Math.random() * 10;    // [0.0, 10.0)
int i10 = (int)(Math.random() * 10); // [0, 9] 均勻分布
  • 底層共享單例 Random,多線程爭用 CAS 更新種子,高併發下成為熱點。
  • 只能產生 double,其他類型需轉換。

第二代:java.util.Random——功能全但同步開銷大

Random rnd = new Random();
int i = rnd.nextInt(10);        // [0, 9]
long l = rnd.nextLong();
boolean b = rnd.nextBoolean();
double g = rnd.nextGaussian();  // 高斯分布
  • 線程安全(內部 AtomicLong 種子),但多線程競爭同一實例時 CAS 重試開銷大。
  • 每次 new Random() 開銷大,通常做成 static final 單例或 ThreadLocal。

第三代:ThreadLocalRandom (JDK 7+)——為高併發而生

// 無需實例化,靜態調用,當前線程專屬種子,零競爭
int i = ThreadLocalRandom.current().nextInt(10);
long l = ThreadLocalRandom.current().nextLong(100, 200); // [100, 200)
double d = ThreadLocalRandom.current().nextDouble();
  • 每線程獨立種子,無同步開銷,吞吐量遠超 Random。
  • API 豐富,支援區間、流式生成 .ints()。
  • 最佳實踐:JDK 7+ 環境下,所有非安全隨機場景首選 ThreadLocalRandom。

兩大經典避坑指南

陷阱一:Math.round(Math.random() * n) 導致邊界分布不均

Math.random()*10 產生 [0,10),round 使 0.0~0.499→0,0.5~1.499→1,... 9.5~9.999→10。0 和 10 的概率只有內部整數的一半。

正確寫法:

// 產生 [0, n] 均勻整數
int r = (int)(Math.random() * (n + 1));          // 或 Math.floor(Math.random() * (n+1))
// 產生 [0, n) 均勻整數
int r = (int)(Math.random() * n);

陷阱二:Math.abs(rnd.nextInt()) % n 偏離均勻分布

nextInt() 範圍 [-2^31, 2^31-1],abs 後 0 出現概率略大,且取模進一步放大偏差。

正確寫法:

// Random / ThreadLocalRandom 內建無偏區間方法
int r = rnd.nextInt(n);        // [0, n)
int r = rnd.nextInt(lo, hi);   // [lo, hi)  JDK 17+

安全隨機數:SecureRandom

  • 用於加密、Token、Session ID 等安全敏感場景。
  • 基於熵池,生成慢,嚴禁用於高頻業務邏輯。
  • new SecureRandom().nextInt(n)。

總結選型表

場景推薦 API理由
單線程/低併發、簡單腳本Math.random()零依賴、一行代碼
多線程高併發、高性能要求ThreadLocalRandom.current()零競爭、API 豐富、JDK 7+ 標配
需可重現序列(測試、模擬)new Random(seed)固定種子可復現
加密、Token、安全敏感SecureRandom密碼學安全
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved