Motivation

We see five opportunities for improvement in the area of pseudorandom
number generators in Java:

With the existing (JDK8) PRNG classes Random, ThreadLocalRandom,
and SplittableRandom, it is difficult to replace any one of them in
an application with some other algorithm, despite the fact that they
all support pretty much the same set of methods. For example, if an
application uses instances of class Random, it will necessarily
declare variables of type Random, which cannot hold instances of
class SplittableRandom; changing the application to use
SplittableRandom would require changing the type of every variable
(including method parameters) used to hold a PRNG object. The one
exception is that ThreadLocalRandom is a subclass of Random,
purely to allow variables of type Random to hold instances of
ThreadLocalRandom, yet ThreadLocalRandom overrides nearly all the
methods of Random. Interfaces can easily address this.

Classes Random, ThreadLocalRandom, and SplittableRandom all
support such methods as nextDouble() and nextBoolean() as well as
stream-producing methods such as ints() and longs(), but they have
completely independent and nearly copy-and-paste identical
implementations. Refactoring this code would make it easier to
maintain and moreover if properly documented would make it much easier
for third parties to create new PRNG classes that also support the
same complete suite of methods.

During the last year, testing has revealed two new weaknesses in the
algorithm used by class SplittableRandom. On the one hand, a
relatively minor revision can avoid those weaknesses. On the other
hand, a new splittable PRNG algorithm TwinLinear has also been
discovered that is almost as fast, even easier to implement, and
appears to completely avoid the three classes of weakness to which
SplittableRandom is prone.

At least one user (in Oracle Labs) has repeatedly reported that
being able to obtain a stream of PRNG objects from a PRNG would make
it much easier to express his code using streaming methods.

There are many PRNG algorithms in the literature that are not
splittable but are jumpable, a different property that nevertheless
also lends itself to supporting streams of PRNG objects. Currently it
is difficult to take advantage of this property in Java. Examples of
jumpable PRNG algorithms are MRG32k3a, Xorshift1024*, and Xoroshiro128+.

Description

We propose to create four new interfaces: RNG, SplittableRNG,
JumpableRNG, and ArbitrarilyJumpableRNG. Roughly speaking:

RNG would provide methods named ints, longs, doubles,
nextBoolean, nextInt, nextLong, nextDouble, and nextFloat,
with all their current parameter variations.

SplittableRNG would extend RNG and also provide methods named
split and splits.

JumpableRNG would extend RNG and also provide methods named
jump and jumps.

ArbitrarilyJumpableRNG would extend JumpableRNG and also provide
additional variations of jump and jumps that allow an arbitrary
jump distance to be specified.

We propose to refactor Random, ThreadLocalRandom, and
SplittableRandom so as to share most of their implementation code.
This refactoring would create new abstract classes AbstractRNG,
AbstractSplittableRNG, AbstractJumpableRNG, and
AbstractArbitrarilyJumpableRNG, each of which requires an extending
class to provide only implementations for methods nextInt(),
nextLong(), and either split() or jump() or jump(distance) if
relevant.

We propose to add a new class TwinLinearRandom that extends
AbstractSplittableRNG (and therefore implements SplittableRNG and
RNG). (The current prototype version of this class requires just 70
lines of code.)

We will review existing use of random number generation in the JDK and possibly refactor to use the new interfaces.

Alternatives

We considered simply introducing new interfaces while leaving the
implementations of Random, ThreadLocalRandom, and
SplittableRandom as is. This would help to make PRNG objects more
easily interchangeable but would not make it any easier to implement
them.

We considered refactoring Random, ThreadLocalRandom, and
SplittableRandom without changing their functionality or adding any
new interfaces. We believe this would reduce their overall memory
footprint, but do nothing to make future PRNG algorithms easier to
implement or use.

Testing

All existing tests for Random, ThreadLocalRandom,
and SplittableRandom should continue to be used.

New test, probably to be applied just once:
The output of the refactored versions of Random,
ThreadLocalRandom, and SplittableRandom (before repairing the
two newly detected weaknesses) should be spot-checked against the
existing (JDK8) implementations to verify that their behavior
remains unchanged.

New test, probably to be applied just once:
The output of TwinLinear should be spot-checked against the C-coded
versions used for quality verification with TestU01 and PractRand.

New test, to become permanent part of test suite:
The jump() methods should be tested to verify that they do travel
around the state cycle by the claimed distance. For example,
starting from any specific initial state, the sequence of operations
nextLong(); jump() ought to leave a generator in the same state as
the sequence of operations jump(); nextLong().