java 生成1-100随机数(附带源码)
一、项目背景详细介绍
在日常开发和测试场景中,经常需要生成随机数来模拟用户输入、测试边界条件、实现简单游戏或抽奖功能。Java 标准库提供了多种生成随机数的方式,包括 java.util.Random、Math.random() 和更现代的 ThreadLocalRandom。掌握如何在指定范围内生成随机整数,是熟悉随机性、概率和伪随机数生成器(PRNG)原理的重要基础,同时也能帮助开发者在性能与线程安全之间做出合适的权衡。
本项目将以“生成 1 到 100 之间的随机整数”为例,演示多种 Java 实现方式,并对比各自的优缺点、线程安全性以及性能适用场景。
二、项目需求详细介绍
本项目需要实现以下功能和特性:
-
生成单个随机数
-
返回一个范围在 1(含)到 100(含)之间的随机整数。
-
支持三种实现方式:
Math.random()、java.util.Random、ThreadLocalRandom。
-
-
批量生成随机数
-
接受参数
count,一次性生成指定个数的随机数列表,并返回List<Integer>或int[]。
-
-
指定范围生成
-
将范围参数化,支持自定义最小值
min与最大值max,并保证返回值在[min, max]范围内。
-
-
并发安全生成
-
在多线程环境下,确保生成效率与正确性,演示如何使用
ThreadLocalRandom或SplittableRandom。
-
-
命令行工具模式
-
提供命令行入口,支持参数:
-
-n, --number:生成单个随机数 -
-c, --count <count>:生成批量随机数 -
-min <min> -max <max>:指定自定义范围
-
-
-
单元测试覆盖
-
使用 JUnit 5 对不同实现及边界情况(如
min > max、count = 0)进行测试,覆盖率 ≥ 90%。
-
-
工程化和可扩展性
-
抽象成
RandomGenerator接口,支持插件式添加新算法(如SecureRandom)。
-
三、相关技术详细介绍
-
Math.random()
-
静态方法,返回
[0.0, 1.0)范围的double,通过乘法与强转实现整数范围随机。 -
简单易用,但在并发环境中仍共享同一个 PRNG,性能和线程安全有限。
-
-
java.util.Random
-
经典伪随机数生成器,可通过种子构造;
-
线程安全(内部使用原子操作),但在高并发场景下会有竞争;
-
提供丰富方法:
nextInt(bound)、nextDouble()、nextGaussian()等。
-
-
java.util.concurrent.ThreadLocalRandom
-
Java 7 引入,为多线程优化的 PRNG;
-
基于线程本地变量,消除多线程竞争,性能远优于
Random; -
只可在多线程中通过
ThreadLocalRandom.current()获取。
-
-
java.util.SplittableRandom
-
Java 8 引入,提供更高质量的伪随机性和并行流友好性;
-
支持
split()方法将生成器分裂,用于并行任务。
-
-
命令行解析
-
Apache Commons CLI:定义、解析参数,生成帮助文档。
-
-
单元测试
-
JUnit 5:测试不同实现在边界和并发场景的正确性和性能。
-
四、实现思路详细介绍
-
接口设计
-
定义
public interface RandomGenerator { int nextInt(int min, int max); } -
三个实现类:
-
MathRandomGenerator:使用Math.random(); -
UtilRandomGenerator:封装java.util.Random实例; -
ThreadLocalRandomGenerator:使用ThreadLocalRandom.current();
-
-
-
单个随机数生成
-
在
nextInt(min, max)方法中,将Math.random() * (max - min + 1)加上min强转为int; -
在
Random.nextInt(bound)基础上偏移; -
在
ThreadLocalRandom.current().nextInt(min, max + 1)直接调用。
-
-
批量生成
-
提供工具方法
List<Integer> generateBatch(int min, int max, int count, RandomGenerator gen); -
使用循环或
IntStream.range(0, count).map(i -> gen.nextInt(min, max)).boxed().collect(...);
-
-
命令行入口
-
Main类解析-n、-c、-min、-max参数; -
根据有无
-c决定调用单个或批量生成; -
可选参数
-impl math|util|threadlocal选择实现。
-
-
并发场景演示
-
使用多线程池测试
UtilRandomGenerator与ThreadLocalRandomGenerator生成大量随机数,统计耗时并对比。
-
-
单元测试策略
-
测试在各种范围和值时是否符合边界;
-
测试
count = 0返回空集合; -
并发测试:多线程同时调用
nextInt结果无异常、均在范围内。
-
五、完整实现代码
// 文件:pom.xml
/*
Maven 项目对象模型,管理依赖与构建
*/
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>random-demo</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Commons CLI 用于命令行解析 -->
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<!-- JUnit 5 用于单元测试 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Surefire 插件运行测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
</plugins>
</build>
</project>
--------------------------------------------------------------------------------
// 文件:src/main/java/com/example/random/RandomGenerator.java
package com.example.random;
/**
* 随机数生成器接口,定义在[min, max]范围内生成整数的方法
*/
public interface RandomGenerator {
/**
* 生成指定范围内的随机整数
* @param min 下限(包含)
* @param max 上限(包含)
* @return 随机整数
*/
int nextInt(int min, int max);
}
--------------------------------------------------------------------------------
// 文件:src/main/java/com/example/random/MathRandomGenerator.java
package com.example.random;
/**
* 基于 Math.random() 的实现
*/
public class MathRandomGenerator implements RandomGenerator {
@Override
public int nextInt(int min, int max) {
if (min > max) {
throw new IllegalArgumentException("min 不能大于 max");
}
// Math.random() 返回 [0.0,1.0),转换为 [min,max]
return min + (int)(Math.random() * (max - min + 1));
}
}
--------------------------------------------------------------------------------
// 文件:src/main/java/com/example/random/UtilRandomGenerator.java
package com.example.random;
import java.util.Random;
/**
* 基于 java.util.Random 的实现
*/
public class UtilRandomGenerator implements RandomGenerator {
private final Random random = new Random();
@Override
public int nextInt(int min, int max) {
if (min > max) {
throw new IllegalArgumentException("min 不能大于 max");
}
// nextInt(bound) 返回 [0,bound),偏移后得到 [min,max]
return min + random.nextInt(max - min + 1);
}
}
--------------------------------------------------------------------------------
// 文件:src/main/java/com/example/random/ThreadLocalRandomGenerator.java
package com.example.random;
import java.util.concurrent.ThreadLocalRandom;
/**
* 基于 ThreadLocalRandom 的实现,适用于多线程场景
*/
public class ThreadLocalRandomGenerator implements RandomGenerator {
@Override
public int nextInt(int min, int max) {
if (min > max) {
throw new IllegalArgumentException("min 不能大于 max");
}
// ThreadLocalRandom.current() 提供高效线程安全生成
return ThreadLocalRandom.current().nextInt(min, max + 1);
}
}
--------------------------------------------------------------------------------
// 文件:src/main/java/com/example/cli/Main.java
package com.example.cli;
import com.example.random.*;
import org.apache.commons.cli.*;
import java.util.ArrayList;
import java.util.List;
/**
* Main 类处理命令行参数,生成随机数
*/
public class Main {
public static void main(String[] args) {
Options options = new Options();
options.addOption("n", "number", false, "生成一个随机数");
options.addOption("c", "count", true, "生成多个随机数,指定数量");
options.addOption(null, "min", true, "随机数下限,默认为1");
options.addOption(null, "max", true, "随机数上限,默认为100");
options.addOption(null, "impl", true, "实现方式:math|util|threadlocal,默认threadlocal");
HelpFormatter formatter = new HelpFormatter();
CommandLineParser parser = new DefaultParser();
try {
CommandLine cmd = parser.parse(options, args);
int min = Integer.parseInt(cmd.getOptionValue("min", "1"));
int max = Integer.parseInt(cmd.getOptionValue("max", "100"));
String impl = cmd.getOptionValue("impl", "threadlocal");
RandomGenerator gen;
switch (impl) {
case "math": gen = new MathRandomGenerator(); break;
case "util": gen = new UtilRandomGenerator(); break;
default: gen = new ThreadLocalRandomGenerator();
}
// 生成单个随机数
if (cmd.hasOption("n")) {
int r = gen.nextInt(min, max);
System.out.println("随机数: " + r);
}
// 生成多个随机数
else if (cmd.hasOption("c")) {
int count = Integer.parseInt(cmd.getOptionValue("c"));
List<Integer> list = new ArrayList<>();
for (int i = 0; i < count; i++) {
list.add(gen.nextInt(min, max));
}
System.out.println("随机数列表: " + list);
}
// 无效调用,打印帮助
else {
formatter.printHelp("java -jar random-demo.jar", options);
}
} catch (Exception e) {
System.err.println("执行异常: " + e.getMessage());
formatter.printHelp("java -jar random-demo.jar", options);
}
}
}
--------------------------------------------------------------------------------
// 文件:src/test/java/com/example/random/RandomGeneratorTest.java
package com.example.random;
import org.junit.jupiter.api.Test;
import java.util.concurrent.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* 各实现及边界的单元测试
*/
public class RandomGeneratorTest {
@Test
void testMathRandomSingle() {
RandomGenerator gen = new MathRandomGenerator();
int r = gen.nextInt(1, 100);
assertTrue(r >= 1 && r <= 100);
}
@Test
void testUtilRandomSingle() {
RandomGenerator gen = new UtilRandomGenerator();
int r = gen.nextInt(10, 20);
assertTrue(r >= 10 && r <= 20);
}
@Test
void testThreadLocalRandomSingle() {
RandomGenerator gen = new ThreadLocalRandomGenerator();
int r = gen.nextInt(5, 5);
assertEquals(5, r);
}
@Test
void testInvalidRange() {
RandomGenerator gen = new MathRandomGenerator();
assertThrows(IllegalArgumentException.class, () -> gen.nextInt(10, 1));
}
@Test
void testBatchGeneration() {
RandomGenerator gen = new UtilRandomGenerator();
int count = 1000;
for (int i = 0; i < count; i++) {
int r = gen.nextInt(1, 100);
assertTrue(r >= 1 && r <= 100);
}
}
@Test
void testConcurrencyPerformance() throws InterruptedException {
RandomGenerator gen1 = new UtilRandomGenerator();
RandomGenerator gen2 = new ThreadLocalRandomGenerator();
int threads = 10, per = 10000;
ExecutorService pool = Executors.newFixedThreadPool(threads);
// 并发调用,不保证输出,只要不抛异常
for (int i = 0; i < threads; i++) {
pool.submit(() -> {
for (int j = 0; j < per; j++) {
int r1 = gen1.nextInt(1, 100);
int r2 = gen2.nextInt(1, 100);
assertTrue(r1 >= 1 && r1 <= 100);
assertTrue(r2 >= 1 && r2 <= 100);
}
});
}
pool.shutdown();
assertTrue(pool.awaitTermination(5, TimeUnit.SECONDS));
}
}
六、代码详细解读
-
RandomGenerator 接口
定义nextInt(int min, int max)方法,实现不同算法的一致调用方式。 -
MathRandomGenerator
-
使用
Math.random(),通过min + (int)(Math.random() * (max-min+1))生成随机数; -
适合简单场景,但每次调用都要执行浮点运算,且在多线程环境下使用同一 PRNG 实例。
-
-
UtilRandomGenerator
-
封装
java.util.Random实例;内部线程安全但在高并发时存在内部锁竞争; -
调用
random.nextInt(bound),偏移后得到目标范围。
-
-
ThreadLocalRandomGenerator
-
使用
ThreadLocalRandom.current(),基于线程本地的 PRNG; -
消除多线程竞争,性能优于
Random,推荐在多线程场景下使用。
-
-
Main 类
-
使用 Commons CLI 解析
-n、-c、--min、--max、--impl参数; -
不带参数时打印帮助;
-
根据
impl选择实现类,分别执行单个或批量随机数生成并输出。
-
-
RandomGeneratorTest 单元测试
-
覆盖三种实现的单值生成、边界情况(
min==max、min>max)抛异常; -
批量生成测试确保多次调用依然在正确范围;
-
并发性能测试:创建 10 个线程、每线程 10000 次调用,验证无异常并在合理时间内完成。
-
七、项目详细总结
本项目通过三种不同方式在 Java 中生成指定范围的随机整数:
-
Math.random():最简单,但性能和并发安全有限;
-
java.util.Random:线程安全,但多线程竞争明显;
-
ThreadLocalRandom:Java 7 引入,基于线程本地变量,性能卓越,推荐并发环境使用。
项目采用接口抽象与多实现的设计模式,命令行工具提供灵活参数配置,JUnit 测试覆盖了边界与并发场景,保证了正确性与可靠性。
八、项目常见问题及解答
Q1:为什么不要直接用 Math.random()?
A:Math.random() 底层共享同一个 Random 实例,多线程时有同步开销,且无法指定种子。
Q2:ThreadLocalRandom 只能在多线程中用吗?
A:可以在单线程中使用,但主要优势在于消除了线程间竞争,在多线程场景性能更好。
Q3:如何生成安全级别的随机数?
A:使用 java.security.SecureRandom,适用于加密场景,但性能相对较低。
Q4:如何生成随机浮点数或 Gaussian 分布?
A:在 Random 或 ThreadLocalRandom 上调用 nextDouble() 或 nextGaussian() 即可。
Q5:如何确保生成的随机序列可重复?
A:对 UtilRandomGenerator 或 SecureRandom 提供固定种子构造,然后在每次运行时使用相同种子。
九、扩展方向与性能优化
-
SecureRandom 实现
添加SecureRandomGenerator,满足安全场景需求。 -
SplittableRandom 实现
引入SplittableRandom,利用其更优质的随机性和并行友好性。 -
并行流批量生成
使用IntStream.range(0, count).parallel().map(i -> gen.nextInt(min,max)).toArray()实现批量并发生成。 -
自定义分布
扩展接口支持不同分布(如正态、泊松),结合 Commons Math 提供更丰富的概率分布。 -
可视化与统计
集成前端或命令行直方图输出,展示生成频率分布情况,验证随机性质量。 -
高性能基准测试
使用 JMH 对三种实现及扩展算法进行微基准测试,量化吞吐量与延迟,为生产环境选型提供数据支撑。
更多推荐
所有评论(0)