Generating pseudorandom data
There are 2 types of random generators in Java: pseudorandom and secure. Pseudorandom generators are transforming a seed into a new portion of pseudorandom data based on some formula. Secure random generators are using some machine specific sources of actually random events (file/socket access, for example) to generate its data.
Secure random generators:
- should be used only when cryptographically strong random data is required
- are slow
could be waiting for external events (“stuck”) if you have requested a lot of random data (Linux
/dev/randomis an example of such generator)
Pseudorandom generators, on the other hand, depend only on the initial “seed” value, so you can generate the same sequence of pseudorandom events if you will provide the same seed to the algorithm. In general case, such generators are fast because they are CPU bound only (do not rely on any IO). We will review the evolution of pseudorandom generators in Java and the reasons behind these changes.
java.util.Random is available from Java 1.0. It is a thread safe class, so you may share (in theory) instances of this class between several threads and do not expect to get the same random data in 2 threads at the same time. Such thread safety is achieved via using an
AtomicLong for the generator seed.
AtomicLong CAS (compare-and-set) operations for updating its seed. Despite being a light non-blocking primitive used in a lot of non-blocking algorithms, CAS behaves really poorly under the high contention. Wait for test results to see how poorly it behaves.
java.util.concurrent.ThreadLocalRandom was added in Java 7 as an attempt to overcome all performance issues associated with
java.util.Random. This new class extends
java.util.Random, so you may pass it to all logic expecting the old
Here are main
ThreadLocalRandom implementation details:
Internally it does not use an
Random. Instead it uses an ordinary
You can not create an instance of
ThreadLocalRandomyourself, because its constructor is not public. Instead you should use its static factory
ThreadLocalRandom.current(). This factory method queries internal
It is CPU-cache aware, so it uses 8
longdummy fields for padding, thus pushing anything else out of its 64 byte L1 cache line.
All of these changes are important, which will be revealed by the following tests.