Java随机数生成方法详解
从现在开始,我们要努力学习啦!今天我给大家带来《如何在Java中使用Random生成随机数》,感兴趣的朋友请继续看下去吧!下文中的内容我们主要会涉及到等等知识点,如果在阅读本文过程中有遇到不清楚的地方,欢迎留言呀!我们一起讨论,一起学习!
Java中生成随机数的核心是java.util.Random类,它通过算法生成伪随机数,支持整数、浮点数和布尔值等类型;可通过指定种子实现序列复现,适用于测试场景;与Math.random()相比,Random提供更丰富的类型支持和种子控制;生成指定范围随机数需结合公式调整;在高并发下建议使用ThreadLocalRandom以避免性能瓶颈,安全敏感场景则应选用SecureRandom。

Java中生成随机数的核心在于使用java.util.Random类。它提供了一系列方法来生成不同数据类型(如整数、浮点数、布尔值)的伪随机数。简单来说,就是先创建一个Random实例,然后调用它提供的方法来获取你想要的随机数。
解决方案
在Java里,我们想搞点随机性,java.util.Random这个类就是我们的得力助手。它能生成各种类型的伪随机数,从整数到浮点数,甚至布尔值都能搞定。
最基础的用法是这样的:
import java.util.Random;
public class RandomExample {
public static void main(String[] args) {
Random random = new Random(); // 创建一个Random实例
// 生成一个任意范围的int整数(正负都可能)
int randomInt = random.nextInt();
System.out.println("任意int随机数: " + randomInt);
// 生成一个[0, bound)范围的int整数,不包含bound
// 比如生成[0, 100)的整数,也就是0到99
int randomIntBounded = random.nextInt(100);
System.out.println("0到99的随机数: " + randomIntBounded);
// 生成一个任意范围的long整数
long randomLong = random.nextLong();
System.out.println("任意long随机数: " + randomLong);
// 生成一个[0.0, 1.0)范围的float浮点数
float randomFloat = random.nextFloat();
System.out.println("0.0到1.0的随机浮点数: " + randomFloat);
// 生成一个[0.0, 1.0)范围的double浮点数
double randomDouble = random.nextDouble();
System.out.println("0.0到1.0的随机双精度浮点数: " + randomDouble);
// 生成一个随机的布尔值
boolean randomBoolean = random.nextBoolean();
System.out.println("随机布尔值: " + randomBoolean);
// 有时候,我们希望随机数序列是可重复的,这在测试或模拟时很有用。
// 这时可以给Random传入一个种子(seed)。
Random seededRandom = new Random(12345L); // 使用固定的种子
System.out.println("\n使用固定种子12345L生成的随机数序列:");
System.out.println("第一个随机数: " + seededRandom.nextInt(100));
System.out.println("第二个随机数: " + seededRandom.nextInt(100));
// 如果再次用12345L作为种子创建Random实例,会得到相同的序列
}
}值得一提的是,Random类生成的是“伪随机数”,这意味着它们并不是真正意义上的随机,而是通过一个确定性的算法从一个初始种子(seed)计算出来的。如果你不指定种子,Random会使用当前时间作为默认种子,这样每次运行程序得到的序列就不同了。但如果你提供了相同的种子,每次运行都会得到相同的随机数序列,这在调试或需要可复现结果的场景下非常有用。
Random类与Math.random()有什么区别?我应该选择哪个?
说实话,这可能是初学者最常问的问题之一。Random类和Math.random()都能生成随机数,但它们之间确实存在一些关键区别,决定了你在不同场景下的选择。
首先,Math.random()是一个静态方法,它直接返回一个double类型的伪随机数,范围是[0.0, 1.0)。它的实现其实是内部调用了一个Random实例。所以,你可以把它看作是new Random().nextDouble()的一个简化版本,但你无法控制它的种子,也无法直接生成其他类型的随机数(比如int或long),除非你手动进行类型转换和范围计算。
而Random类,正如我们前面看到的,是一个实实在在的类,你需要先实例化它。它提供了更丰富的方法,不仅仅是double,还有nextInt()、nextLong()、nextBoolean()、nextFloat()等。更重要的是,你可以通过构造函数传入一个long类型的种子,从而控制随机数序列的可复现性。
那么,到底选哪个呢?
- 如果你只是需要一个快速的、介于0.0和1.0之间的
double类型随机数,并且不关心种子、不涉及高并发,那么Math.random()用起来确实很方便。 比如,我有时候写个小测试,需要随机决定某个操作是否执行,if (Math.random() < 0.5)这种写法就挺顺手。 - 但如果你需要更灵活的控制,比如生成特定范围的整数、生成不同数据类型的随机数、或者需要一个可复现的随机数序列(比如为了单元测试),那么毫无疑问,
Random类是你的首选。 我个人觉得,养成使用Random类的习惯会更好,因为它提供了更多的可能性和控制力,让你能更精确地表达你的“随机”意图。尤其是在生产环境中,你可能需要对随机数的行为有更细致的掌控。
如何生成指定范围内的随机整数或浮点数?
生成指定范围内的随机数,这是我们日常开发中非常普遍的需求。Random类虽然提供了nextInt(int bound),但它只能生成[0, bound)范围的数。如果我们要自定义范围,比如[min, max],就需要一点小技巧了。
1. 生成指定范围 [min, max] 的随机整数(包含min和max):
这个公式是random.nextInt(max - min + 1) + min。
我们来拆解一下:
max - min + 1:这计算的是这个范围里总共有多少个整数。比如[5, 10],就是10 - 5 + 1 = 6个数字(5, 6, 7, 8, 9, 10)。random.nextInt(max - min + 1):这会生成一个[0, max - min + 1)范围的随机数。+ min:最后加上min,就把这个[0, count)的范围平移到了[min, max]。
import java.util.Random;
public class RandomRangeInt {
public static void main(String[] args) {
Random random = new Random();
// 生成一个[1, 100]之间的随机整数 (包含1和100)
int min = 1;
int max = 100;
int randomNumber = random.nextInt(max - min + 1) + min;
System.out.println("在[" + min + ", " + max + "]范围内的随机整数: " + randomNumber);
// 另一个例子:生成一个[-50, 50]之间的随机整数
min = -50;
max = 50;
randomNumber = random.nextInt(max - min + 1) + min;
System.out.println("在[" + min + ", " + max + "]范围内的随机整数: " + randomNumber);
}
}2. 生成指定范围 [min, max) 的随机浮点数(包含min,不包含max):
对于浮点数,nextDouble()和nextFloat()默认生成的是[0.0, 1.0)。要把它映射到[min, max),公式是random.nextDouble() * (max - min) + min。
random.nextDouble():得到一个[0.0, 1.0)的数。* (max - min):将这个数缩放到[0.0, max - min)的范围。+ min:最后加上min,就平移到了[min, max)。
import java.util.Random;
public class RandomRangeDouble {
public static void main(String[] args) {
Random random = new Random();
// 生成一个[10.0, 20.0)之间的随机双精度浮点数 (包含10.0,不包含20.0)
double min = 10.0;
double max = 20.0;
double randomDouble = random.nextDouble() * (max - min) + min;
System.out.println("在[" + min + ", " + max + ")范围内的随机浮点数: " + randomDouble);
// 另一个例子:生成一个[-5.0, 5.0)之间的随机浮点数
min = -5.0;
max = 5.0;
randomDouble = random.nextDouble() * (max - min) + min;
System.out.println("在[" + min + ", " + max + ")范围内的随机浮点数: " + randomDouble);
}
}这些小公式看起来简单,但却是随机数生成里最常用、也最容易出错的地方。特别是整数范围的+1,如果忘了,就会导致max值永远无法生成。
Random类的线程安全性如何?在高并发场景下有什么替代方案?
这是一个非常实际的问题,尤其是在构建高性能、多线程应用时,我们必须考虑Random类的线程安全性及其潜在的性能瓶颈。
java.util.Random类本身是线程安全的。它的所有next方法(比如nextInt(), nextDouble()等)都使用了synchronized关键字进行同步。这意味着,如果你在多个线程中共享同一个Random实例,每次只有一个线程能够调用它的next方法,其他线程必须等待。
问题出在哪呢?
虽然线程安全,但这种同步机制在高并发场景下可能会成为性能瓶颈。多个线程频繁地去争抢同一个Random实例的锁,会导致线程上下文切换的开销,降低程序的吞吐量。想象一下,一堆人排队去一个窗口办业务,即使窗口能保证每个人都办好,但队伍太长,效率自然就低了。
那么,在高并发场景下,我们有什么更好的替代方案呢?
java.util.concurrent.ThreadLocalRandom(Java 7及更高版本) 这是在高并发场景下生成随机数的首选方案。ThreadLocalRandom是Random的子类,它利用了ThreadLocal的原理。简单来说,每个线程都会拥有自己独立的Random实例。这样一来,线程之间就不会存在竞争,也就没有了锁的开销,性能自然就上去了。import java.util.concurrent.ThreadLocalRandom; public class ThreadLocalRandomExample { public static void main(String[] args) { // 获取当前线程的ThreadLocalRandom实例 ThreadLocalRandom current = ThreadLocalRandom.current(); // 用法与Random类似,但无需实例化 int randomNumber = current.nextInt(1, 101); // 生成[1, 100]的随机整数 double randomDouble = current.nextDouble(0.0, 1.0); // 生成[0.0, 1.0)的随机双精度浮点数 System.out.println("ThreadLocalRandom生成的整数: " + randomNumber); System.out.println("ThreadLocalRandom生成的浮点数: " + randomDouble); // 模拟多线程使用 Runnable task = () -> { ThreadLocalRandom tlr = ThreadLocalRandom.current(); System.out.println(Thread.currentThread().getName() + " 生成随机数: " + tlr.nextInt(1000)); }; for (int i = 0; i < 5; i++) { new Thread(task, "Thread-" + i).start(); } } }ThreadLocalRandom的优点是显而易见的:高性能,因为它消除了多线程之间的竞争。缺点嘛,可能就是你不能像Random那样手动设置一个全局的种子来复现整个随机序列,因为每个线程都有自己的种子。但对于大多数并发随机数生成的需求,这都不是问题。java.security.SecureRandom这个类主要用于加密安全的随机数生成。它与Random的主要区别在于,SecureRandom生成的随机数具有更高的不可预测性,更难以被猜测,因此更适合用于生成密钥、安全令牌等对安全性要求极高的场景。import java.security.SecureRandom; public class SecureRandomExample { public static void main(String[] args) { SecureRandom secureRandom = new SecureRandom(); byte[] bytes = new byte[16]; secureRandom.nextBytes(bytes); // 生成随机字节数组 System.out.println("SecureRandom生成的随机字节: " + bytes[0]); int randomNumber = secureRandom.nextInt(100); System.out.println("SecureRandom生成的整数: " + randomNumber); } }SecureRandom的性能通常比Random和ThreadLocalRandom要低,因为它需要执行更复杂的算法来确保随机数的质量。所以,除非你真的需要加密级别的随机性,否则不建议在普通的业务逻辑中使用SecureRandom,以免造成不必要的性能开销。
总结一下我的建议:
- 单线程或低并发:
java.util.Random足够好用,简单直接。 - 高并发场景:毫无疑问选择
java.util.concurrent.ThreadLocalRandom,它能提供最佳的性能。 - 安全敏感场景(如密码学):必须使用
java.security.SecureRandom,牺牲一点性能换取更高的安全性。
选择合适的随机数生成器,是编写健壮、高效Java应用的一个小细节,但往往这些小细节决定了整体的质量。
今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~
JS负载均衡配置全攻略
- 上一篇
- JS负载均衡配置全攻略
- 下一篇
- Python提取数字的实用技巧
-
- 文章 · java教程 | 6分钟前 |
- JavaSocket编程实战教程
- 357浏览 收藏
-
- 文章 · java教程 | 17分钟前 |
- Java十六进制转二进制保留零方法
- 166浏览 收藏
-
- 文章 · java教程 | 27分钟前 |
- JavaIOException常见问题与解决方法
- 428浏览 收藏
-
- 文章 · java教程 | 41分钟前 |
- final关键字的作用及使用场景
- 444浏览 收藏
-
- 文章 · java教程 | 53分钟前 |
- SpringSecurity配置H2数据库控制台步骤
- 434浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- OpenSearch字段Terms查询无结果解决方法
- 116浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- Java长期稳定运行优化方案
- 445浏览 收藏
-
- 文章 · java教程 | 1小时前 | 排序 集合 Lambda表达式 comparator List.sort
- JavaLambda排序实战教程
- 197浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- Java订单管理与统计实现技巧
- 458浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- 0/1背包问题解法与优化方法
- 127浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3182次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3393次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3425次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4530次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3802次使用
-
- 提升Java功能开发效率的有力工具:微服务架构
- 2023-10-06 501浏览
-
- 掌握Java海康SDK二次开发的必备技巧
- 2023-10-01 501浏览
-
- 如何使用java实现桶排序算法
- 2023-10-03 501浏览
-
- Java开发实战经验:如何优化开发逻辑
- 2023-10-31 501浏览
-
- 如何使用Java中的Math.max()方法比较两个数的大小?
- 2023-11-18 501浏览

