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:

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:

ClassQualitySpeedPeriodWhen to use
java.util.Random LowMedium248

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.

ThreadLocalRandom MediumFast264 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.
SecureRandom Very HighSlow2160 Used where you need very high quality or cryptographic strength random numbers. For more information, see explanation of SecureRandom.
SplittableRandom MediumFast264 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 physical dice.

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 further alternatives:

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 applications.

If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.