Managing randomness in Java

If you already had to manage some degree of randomness on Java, chances are you got acquainted with the Math.random() methods. However, the previous method returns a double. Beyond very basic use-cases, another option has to be considered, in the form of the java.util.Random class.


An instance of this class is used to generate a stream of pseudorandom numbers.
— JavaDoc

This root class provides basic random numbers generation capabilities, nothing mind-blowing.

  • Generate a single random:
    • boolean
    • byte array
    • double
    • float, whether uniform or from a Gaussian distribution
    • long
    • or int (from 0 to 232 or a specific bound)
  • Generate a stream of random:
    • int
    • long
    • or double

For more specialized needs, there are two children classes, ThreadLocalRandom and SecureRandom.

random class hierarchy
Figure 1. Random class hierarchy


One problem about the Random class is that it’s based on an AtomicLong for number generation. It’s thread-safe by definition, but it may cause performance issue if used by too many of threads at once.

Use of ThreadLocalRandom is particularly appropriate when multiple tasks (for example, each a ForkJoinTask) use random numbers in parallel in thread pools.
— JavaDoc

Usage is like:

ThreadLocalRandom.current().nextX(...) // (where X is Int, Long, etc.)

There are some interesting things about ThreadLocalRandom:

  • Compared to Random, it adds additional random-generating methods with bounds for types long and double
  • It doesn’t use the next(int bits) for the other random-generating methods, to avoid the AtomicLong contention


The important bit about Random is that it doesn’t provide true randomness, but only pseudo-randomness. From the JavaDoc of the next(int bits)(upon which all other random generator methods depend):

This is a linear congruential pseudorandom number generator, as defined by D. H. Lehmer and described by Donald E. Knuth in The Art of Computer Programming, Volume 3: Seminumerical Algorithms, section 3.2.1.
— JavaDoc

On the opposite, SecureRandom offers true randomness:

This class provides a cryptographically strong random number generator (RNG).

A cryptographically strong random number minimally complies with the statistical random number generator tests specified in FIPS 140-2, Security Requirements for Cryptographic Modules, section 4.9.1.

— JavaDoc

This class depends on a:


A Provider provides (sic) some or all parts of the Java Security API. It has a name e.g. SunRsaSign, and a version.


Pretty self-explanatory, e.g. NativePRNG

Both provider and algorithm are platform-dependent. It means that randomness obtained by using SecureRandom is only as good as the provider and algorithm used.

To obtain an instance of the class, one can call either:

  1. One of the available constructors
  2. One of the getInstance() static method
  3. The getInstanceStrong() static method

I’d suggest using the last option, as it will throw an exception if no "strong" random algorithm is available.

A "strong" algorithm is defined by the securerandom.strongAlgorithms security property. Running Security.getProperty("securerandom.strongAlgorithms") on my local dev environment yields NativePRNGBlocking:SUN. I’ll let everyone decide whether an algorithm prefixed with PNRG (Pseudo-Random Number Generator…​) is good enough.

Remember to check $JAVA_HOME/lib/security/java.security to manage the security configuration of your JVM.
Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
Managing randomness in Java
Share this