Random numbers in Java
There are many applications where we need to generate numbers that appear to be "random" or
unpredictable. At its simplest, we can generate a random number in Java with a line
of code such as the following:
int diceRoll = 1 + ThreadLocalRandom.current().nextInt(6);
This is the simplest way to generate a random number in Java and the appropriate method to use in
many cases. However, depending on your application, a more in-depth understanding
of random number generators may be required. For example:
- we may need to generate other data types, such as random longs, doubles etc;
- we may need to know how many numbers the algorithm is suitable for generating;
- we may need strong guarantees about the level of unpredictability or statistical
properties of the random numbers generated (how "like a real dice" are
the numbers generated by the method above? can one user guess another user's secret number?);
- in simulations of non-linear quantities such as network response times, we may need
to generate random numbers with different types of distribution;
- we may have performance or thread-safety concerns.
Read on for more details of these issues and the various options available for generating random numbers in Java.
Random Number Generators (RNGs) in the Java platform
For the reasons outlined above, there are actually various different random number generators in the Java platform.
The following random nubmer generators are currently provided in the Java platform "out of the box", with the Random
base class offering the possibility of custom subclasses:
|Class||Quality||Speed||Period||When to use|
Legacy uses or for subclassing.
The LCG algorithm used by java.lang.Random is a slow, poor-quality
algorithm by comparison to other techniques. It may be suitable for casual use where you need the ability to set a specific seed.
It is still the base class if you
want to plug in your own basic RNG implementation and take advantage of methods that sit on top of it
such as nextDouble(), nextGaussian() etc.
||This is the general-purpose class to use in most cases, unless you need to guarantee that
you are using a specific algorithm, will be working with a very large number of threads or
need to be able to set predictable seeds. For more information,
see the explanation of ThreadLocalRandom.
||Used where you need very high quality or cryptographic strength
random numbers. For more information, see explanation of SecureRandom.
||Medium||Fast||264 per instance
||Used when a very large number of random numbers need to be generated and/or when
large number of separate geneartor instances are needed to perform a joint
task, e.g. for a very large number of threads working together or in certain
divide-and-conquer algorithms. For more information, see explanation of SplittableRandom.
At the time of writing, there is a proposal underway (see JEP 356: Enhanced Pseudo-Random
Number Generators) to add further RNG algorithms to the Java platform.
Random number generation in more detail
The simple line of code above glosses over a lot of complexity.
We want to produce "unpredictable" numbers yet the whole point of computer instructions is that,
for a given input, they are designed to produce a predictable
result. So random number generation algorithms must generally take whatever tiny amount of "physical" randomness
might be available, e.g. the current clock time in milliseconds or nanoseconds1, and then use this as a
seed to generate a sequence that to the observer, appears to be unpredictable.
As well as being unpredictable, we generally want computer-genreated random numbers to have similar statistical
properties to the "real" sources of unpredictability they are simulating. For example, if we write a
routine to simulate rolling a six-sided dice, we would like each of the numbers 1-6 to
come up with equal probability. And if the routine is used to generate two rolls in succession, we would
like it to appear as though the two rolls were completely independent, just as if we were rolling two
In some cases, we need random numbers to be so unpredictable that money or the security of a system depend on it
(i.e. they are cryptographically secure).
For example, if we assign a random encryption key to one user of a web site or remote system, we don't want that user to be able to
determine the next user's encryption key based on the one assigned to them.
A large number of random number generation techniques have been devised over the years to address the above needs. Each one is
generally a tradeoff: how much CPU time and memory usage are we willing to dedicate to achieving the
goals of statistical fairness and unpredictability given our intended use?
Java includes various
random number generators in the standard JDK, and makes it relatively staightforward to plug in additional
algorithms if required.
What to read next
The following pages contain further information on the ranodm number generators listed above, as well as
1. These sources of "physical" randomness or "real unpredictability" are generally referred to as entropy.
Clock time is the most common source, but other sources could include e.g. CPU temperature
sensors, noise from analogue sound card inputs, timings from physical disk activity (in the age of spinny disks at least!),
recent mouse movement etc. With each of these sources, there are whole discussions to be had on how
good a source of entropy they are.
1. What we're describing here is sometimes more specifically called
a uniform random number generator. We could equally have a generator where
numbers occur randomly with some non-linear distribution.
For example, in a later section, we discuss generating
numbers with a normal distribution, which is needed in certain simulation