JavaRush /Java Blog /Random EN /Probability theory in practice or do you know about Rando...
Level 3

Probability theory in practice or do you know about Random

Published in the Random EN group
Probability theory in practice or do you know about Random - 1


There are many sciences in the world that study the theory of probability. And sciences consist of various sections. For example, in mathematics there is a separate section devoted to the study of random events, quantities, etc. But science is not taken lightly. In this case, the theory of probability began to take shape when people tried to understand what patterns there were in throwing dice when playing games of chance. If you look closely, there are many seemingly random things around us. But everything random is not completely random. But more on that later. The Java programming language also has support for random numbers, starting with the first version of the JDK. Random numbers in Java can be used using the java.util.Random class . For testing, we will use tutorialspoint java online compiler . Here is a primitive example of using Random to emulate throwing “dice”, or cubes in Russian:
import java.util.Random;

public class HelloWorld{
    public static void main(String []args){
        Random rnd = new Random();
        int number = rnd.nextInt(6) + 1;
        System.out.println("Random number: " + number);
It would seem that this could be the end of the description of Random , but it’s not that simple. Let's open the description of the java.util.Random class in the Java API. And here we see interesting things. The Random class uses pseudo-random numbers. How so? It turns out that random numbers are not so random?
Probability theory in practice or do you know about Random - 2

Pseudo-randomness java.util.Random

The documentation for the java.util.Random class says that if instances of Random are created with the same seed parameter and the same sequences of actions are performed on the instances, they return identical sequences of numbers. And if we look closely, we can see that Random actually has a constructor that takes some long value as a seed:
Random rnd1 = new Random(1L);
Random rnd2 = new Random(1L);
boolean test = rnd1.nextInt(6) == rnd2.nextInt(6);
System.out.println("Test: " + test);
This example will return true because the seed of both instances is the same. What to do? The default constructor partly solves the problem. Below is an example of the contents of the Random constructor :
public Random() {
	this(seedUniquifier() ^ System.nanoTime());
The default constructor uses the bitwise exclusive OR operation . And for this it uses a long representing the current time and some seed :
private static long seedUniquifier() {
	for (;;) {
		long current = seedUniquifier.get();
		long next = current * 181783497276652981L;
		if (seedUniquifier.compareAndSet(current, next))
			return next;
Another interesting thing here is that each call to the seedUniquifier getter method changes the value of the seedUniquifier . That is, the class is designed to select random numbers as efficiently as possible. However, as the documentation says, they " are not cryptographically secure ". That is, for some purposes of use for cryptographic purposes (password generation, etc.) it is not suitable, because the sequence with the proper approach is predicted. There are examples on this topic on the Internet, for example here: “ Predicting the next Math.random() in Java ”. Or for example the source code here: " Vulnerability Weak Crypto ". java.util.Random (random number generator) has a certain “shortcut”, that is , a shortened version of the call that is executed through Math.random:
public static void main(String []args){
	int random_number = 1 + (int) (Math.random() * 6);
	System.out.println("Value: " + random_number);
But if you look carefully, the same Random sits inside:
public static double random() {
	return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
private static final class RandomNumberGeneratorHolder {
	static final Random randomNumberGenerator = new Random();
The JavaDoc advises using the SecureRandom class for a " cryptographically secure pseudo-random number generator ".
Probability theory in practice or do you know about Random - 3

Secure Random Java

The SecureRandom class is a subclass of java.util.Random and is located in the package . A comparison of these two classes can be read in the article " Difference between java.util.Random and ". Why is this SecureRandom so good? The fact is that for him the source of random numbers is such a magical-sounding thing as the “core entropy pool.” This is both a plus and a minus. You can read about the disadvantages of this in the article: “ The dangers of ”. In short, Linux has a kernel random number generator (RNG). RNG generates random numbers based on data from the entropy pool, which is filled based on random events in the system, such as keyboard and disk timings, mouse movements, interrupts, and network traffic. More information about the entropy pool is described in the material " Random numbers in Linux (RNG) or how to “fill” /dev/random and /dev/urandom ". On Windows systems, SHA1PRNG is used, implemented in With the development of Java, SecureRandom also changed, which is worth reading about in the review “ Java SecureRandom updates as of April 2016 ” for a complete picture.
Probability theory in practice or do you know about Random - 4

Multithreading or be like Caesar

If you look at the code of the Random class , nothing seems to indicate trouble. Methods are not marked synchronized . But there is one BUT: when creating Random with the default constructor in several threads, we will share the same instance seed between them , by which Random will be created . And also when a new random number is received, instance’s internal AtomicLong also changes . On the one hand, there is nothing wrong with this from a logical point of view, because... AtomicLong is used . On the other hand, you have to pay for everything, including productivity. And for this too. Therefore, even the official documentation for java.util.Random says: " Instances of java.util.Random are threadsafe. However, the concurrent use of the same java.util.Random instance across threads may encounter contention and consequent poor performance. Consider instead using ThreadLocalRandom in multithreaded designs ". That is, in multi-threaded applications when actively using Random from several threads, it is better to use the ThreadLocalRandom class . Its usage is slightly different from regular Random :
public static void main(String []args){
	int rand = ThreadLocalRandom.current().nextInt(1,7);
	System.out.println("Value: " + rand);
As you can see, we do not specify a seed for it . This example is described in the official tutorial from Oracle: Concurrent Random Numbers . You can read more about this class in the review: " Guide to ThreadLocalRandom in Java ".
Probability theory in practice or do you know about Random - 5

StreamAPI and Random

With the release of Java 8, we have many new features. Including Stream API. And the changes also affected the generation of Random values. For example, the Random class has new methods that allow you to get a Stream with random values ​​like int, doubleor long. For example:
import java.util.Random;

public class HelloWorld{
    public static void main(String []args){
        new Random().ints(10, 1, 7).forEach(n -> System.out.println(n));
There is also a new class SplittableRandom :
import java.util.SplittableRandom;

public class HelloWorld{
    public static void main(String []args){
        new SplittableRandom().ints(10, 1, 7).forEach(n -> System.out.println(n));
You can read more about the difference between SplittableRandom and other classes here: " Different ways to create Random numbers in Java ".


I think it's worth drawing a conclusion. You need to carefully read the JavaDoc for the classes used. Behind something as simple at first glance as Random there are nuances that can play a cruel joke. #Viacheslav