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.
Random
An instance of this class is used to generate a stream of pseudorandom numbers.
https://docs.oracle.com/javase/8/docs/api/java/util/Random.html
This root class provides basic random numbers generation capabilities, nothing mind-blowing.
- Generate a single random:
boolean
byte
arraydouble
float
, whether uniform or from a Gaussian distributionlong
- 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
.
ThreadLocalRandom
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 ofThreadLocalRandom
is particularly appropriate when multiple tasks (for example, each aForkJoinTask
) use random numbers in parallel in thread pools.
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadLocalRandom.html
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 typeslong
anddouble
- It doesn’t use the
next(int bits)
for the other random-generating methods, to avoid theAtomicLong
contention
SecureRandom
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.
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/Random.java#l188
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.
https://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html
This class depends on a:
- Provider
-
A
Provider
provides (sic) some or all parts of the Java Security API. It has a name e.g.SunRsaSign
, and a version. - Algorithm
-
Pretty self-explanatory, e.g.
NativePRNG
Both provider and algorithm are platform-dependent.
It means that randomness obtained by using |
To obtain an instance of the class, one can call either:
- One of the available constructors
- One of the
getInstance()
static method - 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.
|