39.1 RandomGenerator and SplittableRandom

Generate high‑quality random values using the modern RandomGenerator API (JDK 17+) and the parallel‑friendly SplittableRandom (JDK 8+).

RandomGenerator Basics (JDK 17+)

import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;

// Create a specific algorithm, seeded for reproducibility
RandomGenerator rng = RandomGeneratorFactory
        .of("L64X128MixRandom")
        .create(42L);

int dice = rng.nextInt(1, 7);       // uniform int in [1, 6]
double u   = rng.nextDouble();      // uniform in [0.0, 1.0)
double v   = rng.nextDouble(10.0);  // uniform in [0.0, 10.0)

List available algorithms:

import java.util.random.RandomGeneratorFactory;

RandomGeneratorFactory.all().forEach(f -> System.out.println(f.name()));

Notable algorithms:

  • LXM family (e.g., L64X128MixRandom, L64X256MixRandom): fast, strong statistical quality; good defaults for simulations.
  • Xoshiro/Xoroshiro variants: popular, fast; good for many simulation scenarios.
  • SecureRandom: cryptographically secure for keys/tokens; slower, non‑deterministic across runs.

Stream‑Based Generation

RandomGenerator rng = RandomGeneratorFactory.of("L64X256MixRandom").create();
rng.ints(10, 0, 100).forEach(System.out::println);
rng.doubles(5).forEach(System.out::println);

SplittableRandom (JDK 8+)

SplittableRandom is designed for parallel generation: each split produces an independent child generator.

import java.util.SplittableRandom;

SplittableRandom root = new SplittableRandom(42);
SplittableRandom childA = root.split();
SplittableRandom childB = root.split();

long[] samples = childA.longs(10, 0, 100).toArray();

In parallel tasks, derive a per‑task RNG via split() or a mapped seed (e.g., new SplittableRandom(baseSeed ^ taskId)), avoiding shared generators.

Jumpable/Leapable Generators

Some RandomGenerator implementations support long‑range state advancement:

RandomGenerator g = RandomGeneratorFactory.of("L64X256MixRandom").create(42);
if (g instanceof RandomGenerator.JumpableGenerator jg) {
    RandomGenerator gJumped = jg.jump(); // independent stream far ahead in sequence
}
if (g instanceof RandomGenerator.LeapableGenerator lg) {
    RandomGenerator gLeaped = lg.leap(); // larger leap distance
}

SecureRandom for Cryptography

import java.security.SecureRandom;

SecureRandom sr = SecureRandom.getInstanceStrong();
byte[] token = new byte[32];
sr.nextBytes(token);

Use SecureRandom for keys/tokens/nonces; avoid non‑crypto generators in security contexts.

Monte Carlo π (Deterministic)

RandomGenerator rng = RandomGeneratorFactory.of("L64X128MixRandom").create(123);
int inside = 0;
int n = 1_000_000;
for (int i = 0; i < n; i++) {
    double x = rng.nextDouble();
    double y = rng.nextDouble();
    if (x*x + y*y <= 1.0) inside++;
}
double piEstimate = 4.0 * inside / (double) n;

Practical Guidance

  • Prefer an LXM generator via RandomGeneratorFactory for general simulations.
  • Use SplittableRandom (or Jumpable/Leapable algorithms) for parallel workloads.
  • Seed explicitly and record the algorithm name for reproducibility.
  • Use SecureRandom for any security‑sensitive needs.