Apache Commons RNG 1.7 快速入门与集成示例

以 Apache Commons RNG 1.7 为例,从零创建 Maven 工程引入 commons-rng-simple 与 commons-rng-sampling 依赖,跑通第一个可复现随机数程序,讲清五模块职责、依赖树、与 java.util.Random 及 JDK 17 RandomGenerator 的选型差异和高频坑,命令回显均实测通过。

Apache Commons RNGApache Commons RNG2026/10/15

Apache Commons RNG 1.7 快速入门与集成示例

目标:10 分钟内在 Maven 工程中集成 Apache Commons RNG 1.7,跑通第一个可复现的随机数程序,并讲清模块职责、依赖树与选型边界;本文全部命令与回显均已在 Ubuntu 24.04 + JDK 17 环境实测通过。

Apache Commons RNG 1.7 是 Apache Commons 的伪随机数生成器库,提供 57 种随机源算法与一套分布采样器。它解决的核心痛点是:java.util.Random 算法固定(LCG)、质量有限且无法替换算法,而 Commons RNG 把「算法选择、种子管理、可跳/可分裂并行、分布采样」做成了统一的可插拔 API。本篇聚焦「怎么最快跑起来」:从空目录到可运行的胖 jar;API 细节与算法族对比见本专栏《Apache Commons RNG 1.7 常用 API 与随机源详解》,采样与最佳实践见《Apache Commons RNG 1.7 随机数生成示例与最佳实践详解》。

一、环境信息

本节固定可复现基线,后续命令均在此环境执行。

  • 操作系统:Ubuntu 24.04.5 LTS(PRETTY_NAME="Ubuntu 24.04.5 LTS")
  • 架构:x86_64
  • JDK:OpenJDK 17.0.20.1(Eclipse Temurin 发行版)
  • 构建工具:Apache Maven 3.9.16
  • 组件版本:Apache Commons RNG 1.7(多模块:client-api、core、simple、sampling、bom)
  • Maven 坐标:org.apache.commons:commons-rng-simple:1.7、org.apache.commons:commons-rng-sampling:1.7
  • 工程目录:/root/rng-quick

环境确认(实时回显):

java -version
openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment Temurin-17.0.20.1+1 (build 17.0.20.1+1)
OpenJDK 64-Bit Server VM Temurin-17.0.20.1+1 (build 17.0.20.1+1, mixed mode, sharing)
mvn -version | head -1
Apache Maven 3.9.16 (2bdd9fddda4b155ebf8000e807eb73fd829a51d5)

💡 说明:Commons RNG 1.7 的字节码基线是 Java 8(major version 52,实测见本专栏 Ubuntu 安装指南 FAQ Q5),因此工程用 JDK 8 至 21 均可;本文选 JDK 17 是当前 LTS 主流选择。

二、10 分钟最小可用

本节从空目录开始,创建工程、引入依赖、编写验证程序、编译运行,最终得到一个可独立分发的胖 jar。

2.1 创建工程并引入依赖

mkdir -p /root/rng-quick/src/main/java

pom.xml(完整内容,文件路径 /root/rng-quick/pom.xml):

<?xml version="1.0" encoding="UTF-8"?>
<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.rng</groupId>
  <artifactId>rng-quick</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-rng-simple</artifactId>
      <version>1.7</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-rng-sampling</artifactId>
      <version>1.7</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>rng-quick</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.5.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>RngCheck</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

依赖只有两个:commons-rng-simple(RandomSource 枚举工厂,创建生成器的入口)与 commons-rng-sampling(分布采样器,第一个程序不直接用到,后续示例无需改 pom)。用依赖树确认模块间关系:

cd /root/rng-quick && mvn -B dependency:tree | grep -E "rng-quick:jar|commons-rng"
[INFO] com.example.rng:rng-quick:jar:1.0.0
[INFO] +- org.apache.commons:commons-rng-simple:jar:1.7:compile
[INFO] |  +- org.apache.commons:commons-rng-client-api:jar:1.7:compile
[INFO] |  \- org.apache.commons:commons-rng-core:jar:1.7:compile
[INFO] \- org.apache.commons:commons-rng-sampling:jar:1.7:compile

依赖树解读:simple 传递引入 client-api(接口)与 core(实现),sampling 平级独立——Commons RNG 没有任何第三方传递依赖,整棵树只有它自己的四个模块,集成负担极小。

2.2 编写第一个程序

验证程序 RngCheck.java(文件路径 /root/rng-quick/src/main/java/RngCheck.java):

import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.simple.RandomSource;

public class RngCheck {
    public static void main(String[] args) {
        UniformRandomProvider rng = RandomSource.MT.create(20261015L);
        System.out.println("provider     = " + rng.getClass().getName());
        System.out.println("nextInt()    = " + rng.nextInt());
        System.out.println("nextInt(100) = " + rng.nextInt(100));
        System.out.println("nextLong()   = " + rng.nextLong());
        System.out.println("nextDouble() = " + rng.nextDouble());
        System.out.println("nextBoolean()= " + rng.nextBoolean());
        System.out.println("Commons RNG OK");
    }
}

代码只有两个 API:RandomSource.MT 是 MersenneTwister 算法的枚举值(1.7 共 57 个可选算法),create(20261015L) 用固定长整型种子创建 UniformRandomProvider。固定种子意味着序列可复现——两次运行输出完全一致,这是随机数库调试与测试的刚需。此处特意用枚举实例方法 MT.create(seed) 而非静态 RandomSource.create(MT, seed):后者在 1.7 已标记 @Deprecated(迁移无行为差异,坑点详见第四章)。

2.3 编译与运行

cd /root/rng-quick && mvn -q -B compile; echo EXIT=$?
EXIT=0

以 classpath 方式运行(四模块 jar 由 Maven 本地仓库提供):

R=$HOME/.m2/repository/org/apache/commons
CP=target/classes:$R/commons-rng-simple/1.7/commons-rng-simple-1.7.jar:$R/commons-rng-core/1.7/commons-rng-core-1.7.jar:$R/commons-rng-client-api/1.7/commons-rng-client-api-1.7.jar:$R/commons-rng-sampling/1.7/commons-rng-sampling-1.7.jar
java -Dfile.encoding=UTF-8 -cp $CP RngCheck
provider     = org.apache.commons.rng.core.source32.MersenneTwister
nextInt()    = 243253777
nextInt(100) = 79
nextLong()   = -7428464460000287899
nextDouble() = 0.86954735697081
nextBoolean()= true
Commons RNG OK

再以 shade 打包并 java -jar 运行(免拼 classpath,适合分发):

mvn -q -B package && ls -l target/*.jar
-rw-r--r-- 1 root root   2852 Oct 15 02:28 target/original-rng-quick.jar
-rw-r--r-- 1 root root 419955 Oct 15 02:28 target/rng-quick.jar
java -Dfile.encoding=UTF-8 -jar target/rng-quick.jar
provider     = org.apache.commons.rng.core.source32.MersenneTwister
nextInt()    = 243253777
nextInt(100) = 79
nextLong()   = -7428464460000287899
nextDouble() = 0.86954735697081
nextBoolean()= true
Commons RNG OK

2.4 验证点与预期结果

验证项预期实测
mvn compile退出码 0EXIT=0
provider 类名org.apache.commons.rng.core.source32.MersenneTwister一致
固定种子下 5 个取数值243253777 / 79 / -7428464460000287899 / 0.86954735697081 / true一致
重复运行输出与首次完全相同(可复现)一致
rng-quick.jar约 420 KB 胖 jar419955 字节

两次运行(classpath 与 fat jar)输出逐字节相同,固定种子可复现性得到验证。

三、工程集成要点

本节说明把 Commons RNG 集成进既有工程时的模块取舍与基线确认。

3.1 按需选择模块

需求依赖说明
基础取数(int/long/double/boolean/bytes)commons-rng-simple传递带出 client-api 与 core,最小依赖
按分布采样(高斯/指数/泊松等)加 commons-rng-sampling采样器工厂 Sampler.of(...)
大工程统一版本加 commons-rng-bom(dependencyManagement)五模块版本对齐
直接 new 实现类不建议core 官方明确不建议应用访问,接口可能变化

3.2 JDK 基线与编码

字节码基线 Java 8(major 52),JDK 8/11/17/21 均可运行;本文 pom 用 maven.compiler.release=17 编译应用代码,若目标环境是 JDK 8 改为 8 即可。含中文源码或输出的环境记得 project.build.sourceEncoding=UTF-8 与运行参数 -Dfile.encoding=UTF-8。

3.3 与既有随机数代码共存

Commons RNG 与 java.util.Random 可同 classpath 共存,互不干扰:前者所有 API 在 org.apache.commons.rng 命名空间下。迁移策略上,新代码用 RandomSource.<算法>.create(seed) 获取 UniformRandomProvider,旧代码继续用 Random,按模块逐步替换;需要 Random 适配层的场景可用 RandomSource 创建后包一层(1.7 的 simple 模块还提供 ThreadLocalRandomSource 用于多线程,实测见本专栏最佳实践篇第五章)。

四、高频坑与修复

本节列出集成阶段最容易踩的四个坑,均附实测复现与修复。

4.1 classpath 缺 core 模块:NoClassDefFoundError

jar 直跑时只放 simple 与 client-api 两个 jar(漏掉 core),实测复现:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/rng/core/source32/JDKRandom
        at org.apache.commons.rng.simple.internal.ProviderBuilder$RandomSourceInternal.<clinit>(ProviderBuilder.java:142)
        at org.apache.commons.rng.simple.RandomSource.<clinit>(RandomSource.java:189)
        at RngCheck.main(RngCheck.java:6)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.rng.core.source32.JDKRandom

修复:client-api、core、simple、sampling 四个模块 jar 必须齐全(或用本文 shade 胖 jar 一劳永逸)。Maven 工程无此问题,传递依赖自动处理。

4.2 使用过时的静态工厂 create:deprecated 警告

静态 RandomSource.create(RandomSource, Object, Object...) 在 1.7 已弃用,编译期触发实测警告:

/root/rng-quick/src/main/java/RngCheck.java:6: warning: [deprecation] create(RandomSource,Object,Object...) in RandomSource has been deprecated
        UniformRandomProvider rng = RandomSource.create(RandomSource.MT, 20261015L);
                                                ^
1 warning

修复:改用枚举实例方法 RandomSource.MT.create(20261015L)。实测同种子下两种写法输出完全一致(首个 nextInt 均为 243253777),可放心迁移。

4.3 中文输出乱码

POSIX locale 下 JVM 默认 ASCII 编码,中文变问号。修复:运行加 -Dfile.encoding=UTF-8,或系统 export LANG=C.UTF-8;编译期由 pom 的 project.build.sourceEncoding=UTF-8 保证。

4.4 TWO_CMRES_SELECT 无参创建失败

57 个枚举值中,RandomSource.TWO_CMRES_SELECT 的 create() 会抛 IllegalArgumentException: wrong number of arguments——它是 TwoCmres 算法的自选子循环变体,必须显式传入子周期选择参数;普通用途直接用 TWO_CMRES。其余 56 个算法均可无参或带种子直接创建(全量枚举清单见本专栏 API 详解篇第四章)。

五、选型建议

本节回答「什么时候该用 Commons RNG」,与 JDK 自带能力做正面对比。

维度java.util.RandomJDK 17 RandomGeneratorApache Commons RNG 1.7
算法数量1 种(48 位 LCG)数种(L128X128Mix、Xoshiro、SplitMix 等)57 种(MT、Xoshiro、PCG、LXM、Philox 等)
算法可插拔否接口统一,实现有限枚举全量可枚举、可编程切换
可跳/可分裂(并行)否部分实现Jumpable/LongJumpable/Splittable/ArbitrarilyJumpable 完整体系
分布采样无无内置 40+ 采样器(高斯/泊松/伽马/Dirichlet 等)
状态保存/恢复无无saveState/restoreState 原生支持
最低 JDK1.1178
序列跨平台一致是是是(本文实测 Ubuntu/CentOS 输出一致)

选型建议:简单非关键场景用 java.util.Random 足矣;JDK 17 起新代码可优先 RandomGenerator 家族;需要算法多样性、统计质量、可跳/可分裂并行、分布采样或 Java 8 基线时,Commons RNG 是成熟选择。加密安全随机(密钥、令牌)始终用 SecureRandom,任何伪随机库都不替代它。

六、参考链接

  1. Apache Commons RNG 用户指南:https://commons.apache.org/proper/commons-rng/userguide/rng-userguide.html
  2. Commons RNG 1.7 Javadoc(RandomSource/UniformRandomProvider):https://commons.apache.org/proper/commons-rng/javadocs/api-1.7/
  3. Commons RNG 1.7 发布说明:https://downloads.apache.org/commons/rng/RELEASE-NOTES.txt
  4. Maven 中央仓库坐标:https://repo1.maven.org/maven2/org/apache/commons/commons-rng-simple/
  5. 本专栏姊妹篇:《Ubuntu 22.04 安装 Apache Commons RNG 指南》《Apache Commons RNG 1.7 常用 API 与随机源详解》《Apache Commons RNG 1.7 随机数生成示例与最佳实践详解》