Java中隨機(jī)數(shù)生成的多種方式
Java 中生成隨機(jī)數(shù)是日常開發(fā)中最常見的需求之一:從簡(jiǎn)單的抽獎(jiǎng)、驗(yàn)證碼,到游戲、模擬、測(cè)試數(shù)據(jù),再到安全敏感的密鑰、token 生成,隨機(jī)數(shù)無處不在。
但很多人只知道 Math.random(),其實(shí) Java 提供了多種隨機(jī)數(shù)生成方式,每種適用場(chǎng)景完全不同,用錯(cuò)會(huì)導(dǎo)致性能爆炸、線程安全問題,甚至安全漏洞!
本文從零基礎(chǔ)講到精通,帶你徹底搞懂 Java 隨機(jī)數(shù)的全部玩法。
一、Java 隨機(jī)數(shù)家族全景圖(推薦收藏)
| 方式 | 包路徑 | 隨機(jī)類型 | 線程安全 | 性能(并發(fā)下) | 安全性 | 推薦場(chǎng)景 | JDK 版本 |
|---|---|---|---|---|---|---|---|
| Math.random() | java.lang | 偽隨機(jī) | 是 | 中等 | 低 | 非常簡(jiǎn)單的單線程場(chǎng)景 | 1.0 |
| java.util.Random | java.util | 偽隨機(jī) | 是(但慢) | 差 | 低 | 單線程或低并發(fā)普通隨機(jī) | 1.0 |
| ThreadLocalRandom | java.util.concurrent | 偽隨機(jī) | 每個(gè)線程獨(dú)立 | 極高 | 低 | 高并發(fā)普通隨機(jī)(目前最推薦的普通場(chǎng)景) | 1.7 |
| SecureRandom | java.security | 加密安全隨機(jī) | 是 | 較低 | 高(加密級(jí)) | 密碼、密鑰、token、nonce、驗(yàn)證碼等安全場(chǎng)景 | 1.1 |
| SplittableRandom | java.util | 偽隨機(jī) | 非線程安全 | 高 | 低 | 并行計(jì)算、流式處理(ForkJoinPool 等) | 1.8 |
二、零基礎(chǔ)快速上手(最常用的幾種寫法)
1. 最簡(jiǎn)單的方式(入門必會(huì))
// [0.0, 1.0) 之間的 double double d = Math.random(); // 0 ~ 9 的整數(shù) int num = (int) (Math.random() * 10); // 更推薦:使用 Random(范圍更清晰) Random random = new Random(); int num2 = random.nextInt(10); // [0, 10) int num3 = random.nextInt(5, 15); // [5, 15) JDK 17+ 才支持
2. 生成指定范圍的整數(shù)(最常用寫法)
// 通用寫法:min(包含) ~ max(不包含)
public static int nextInt(int min, int max) {
return min + new Random().nextInt(max - min);
}
// 更高效(推薦)
ThreadLocalRandom.current().nextInt(min, max);
三、三大主流隨機(jī)數(shù)生成器詳細(xì)對(duì)比與源碼級(jí)講解
1. Random(最經(jīng)典,但別亂用)
Random r = new Random(); // 默認(rèn)種子 = 當(dāng)前時(shí)間毫秒 // 或 Random r = new Random(123456789L); // 指定種子 → 可復(fù)現(xiàn) r.nextInt(); // int 全范圍 r.nextInt(100); // [0,100) r.nextBoolean(); r.nextDouble(); // [0.0, 1.0) r.nextGaussian(); // 高斯分布(正態(tài)分布)
缺點(diǎn):
- 多線程下內(nèi)部用 CAS + synchronized,競(jìng)爭(zhēng)激烈時(shí)性能很差
- 種子可預(yù)測(cè)(尤其是用時(shí)間戳),安全性低
2. ThreadLocalRandom(高并發(fā)首選,性能之王)
// 正確用法(不要 new) ThreadLocalRandom random = ThreadLocalRandom.current(); // 用法和 Random 幾乎一樣 int i = random.nextInt(100); int range = random.nextInt(10, 50); // [10,50) long l = random.nextLong(1_000_000); double d = random.nextDouble(0.0, 1.0);
為什么比 Random 快很多?
- 每個(gè)線程擁有獨(dú)立的隨機(jī)數(shù)生成器(ThreadLocal 思想)
- 無鎖、無競(jìng)爭(zhēng)
- 官方推薦:在高并發(fā)場(chǎng)景下替換 Random,性能可提升 3~10 倍
注意:不支持手動(dòng)設(shè)置種子(設(shè)計(jì)上故意禁止),不可復(fù)現(xiàn)。
3. SecureRandom(安全場(chǎng)景必須用)
// 最常用寫法
SecureRandom sr = new SecureRandom(); // 默認(rèn)強(qiáng)隨機(jī)
// 指定算法(常見)
SecureRandom sr2 = SecureRandom.getInstance("NativePRNG");
SecureRandom sr3 = SecureRandom.getInstanceStrong(); // 最安全(但最慢)
byte[] token = new byte[32];
sr.nextBytes(token); // 填充 32 字節(jié)安全隨機(jī)數(shù)
int code = 100_000 + sr.nextInt(900_000); // 6位驗(yàn)證碼
特點(diǎn):
- 種子來自操作系統(tǒng)熵池(鼠標(biāo)移動(dòng)、鍵盤敲擊、硬件中斷等)
- 不可預(yù)測(cè),不可復(fù)現(xiàn)
- 用于:session id、CSRF token、鹽、密鑰、UUID v4 等
性能:比 Random 慢 10~100 倍,但安全第一。
四、常見場(chǎng)景最佳實(shí)踐(直接抄就行)
普通游戲、測(cè)試數(shù)據(jù)、模擬、抽獎(jiǎng)
→ ThreadLocalRandom.current()
Web 后臺(tái)普通隨機(jī)(日志、分配 id 等)
→ ThreadLocalRandom
驗(yàn)證碼、短信碼、找回密碼 token
→ SecureRandom
生成安全密鑰、nonce、簽名鹽
→ SecureRandom.getInstanceStrong() 或 NativePRNG
想要結(jié)果可復(fù)現(xiàn)(調(diào)試、測(cè)試用例)
→ new Random(固定種子)
并行流或 ForkJoinPool 大規(guī)模并行計(jì)算
→ SplittableRandom
五、經(jīng)典誤區(qū)與面試高頻問題
- Math.random() 底層就是 new Random(),多線程下性能差
- Random 是線程安全的,但并發(fā)性能極差
- ThreadLocalRandom 不能 new,只能用 current()
- SecureRandom 不要在循環(huán)里反復(fù) new(很慢),復(fù)用一個(gè)實(shí)例
- 永遠(yuǎn)不要用 Random 生成密碼/密鑰/驗(yàn)證碼(可被預(yù)測(cè)攻擊)
- JDK 17+ 推薦:RandomGenerator 接口統(tǒng)一 API(未來趨勢(shì))
六、終極總結(jié)一句話
- 普通隨機(jī) → ThreadLocalRandom(性能最高)
- 安全隨機(jī) → SecureRandom(安全第一)
- 想要可復(fù)現(xiàn) → new Random(種子)
- 簡(jiǎn)單寫 → Math.random()(但別在高并發(fā)用)
掌握這三大家族,基本覆蓋 99% 的隨機(jī)數(shù)需求。
到此這篇關(guān)于Java中隨機(jī)數(shù)生成的多種方式的文章就介紹到這了,更多相關(guān)Java隨機(jī)數(shù)生成方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)在圖片中添加文字水印的示例代碼
本文介紹了一個(gè)使用Java實(shí)現(xiàn)的圖片水印工具,該工具能夠讀取指定路徑的圖片,在圖片上添加文字水印,并將帶有水印的圖片保存到指定路徑,感興趣的小伙伴可以了解下2026-05-05
springboot使用單元測(cè)試實(shí)戰(zhàn)
這篇文章主要介紹了springboot使用單元測(cè)試實(shí)戰(zhàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09
Java8與Scala中的Lambda表達(dá)式深入講解
這篇文章主要給大家介紹了關(guān)于Java8與Scala中Lambda表達(dá)式的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
Java并發(fā)編程中高頻異常的原因,場(chǎng)景與解決方案全解析
在Java并發(fā)編程中,異常處理是保障程序穩(wěn)定性的核心環(huán)節(jié),本文將深度解析4類高頻并發(fā)異常的產(chǎn)生原因、典型場(chǎng)景,并給出可落地的解決方案,幫你徹底避開這些坑2026-03-03
Java實(shí)現(xiàn)對(duì)象轉(zhuǎn)CSV格式
CSV是一種逗號(hào)分隔值格式的文件,一般用來存儲(chǔ)數(shù)據(jù)的純文本格式文件。Java對(duì)象轉(zhuǎn)CSV,有現(xiàn)成的工具包,commons-lang3 的ReflectionToStringBuilder 就可以簡(jiǎn)單的解決的對(duì)象轉(zhuǎn)CSV,快跟隨小編一起學(xué)習(xí)一下吧2022-06-06
解決IDEA2020.1.2IDEA打不開的問題(最新分享)
由于idea安裝多了某個(gè)jar,點(diǎn)擊出現(xiàn)讀條后閃退情況,接下來通過本文給大家分享解決IDEA2020.1.2IDEA打不開的問題,非常不錯(cuò),具有一定的參考借鑒價(jià)值,感興趣的朋友跟隨小編一起看看吧2020-07-07

