Random vs ThreadLocalRandom Classes in Java
The Random Class of the java.util package is used for generating a stream of pseudorandom numbers. It uses a 48-bit seed, which is amended by implementing a Linear Congruential Formula. The general form of a Linear Congruential Formula is an+1 = k * an + c (mod m) where a0 is the seed, a1, a2, … an, an+1 are the random numbers and k, c, m are constants.
If we create two instances of the Random class with the same seed value and call the same sequence of methods for each, they both will return identical sequences of numbers. This property is enforced by specific algorithms defined for this class. The algorithms use a protected utility method which upon invocation can give up to 32 pseudorandomly generated bits. Instances of Random are thread–safe. Although, if the same instances are used across threads they may suffer from contention and result in poor performance. The Instances of Random are not cryptographically safe and therefore should not be used for security-sensitive applications.
Syntax:
public class Random extends Object implements Serializable
Let us take an example, in the program given below we have three instances of the Random class. The first two have the same seed value passed into its constructor. This results in the same number getting generated when we use the nextInt() method of the Random class. But when we change the value of the seed and use it to create the third instance, the number getting generated is different. This example clearly demonstrates the above-stated fact about the instances generating the same sequence of numbers if the same seed value is used and the same methods are used for both.
Java
// Java Program to illustrate Random class // Importing Random class from java.util utility package import java.util.Random; // Class // Main class extending to parent Random class public class RandomNumbers extends Random { // Main driver method public static void main(String[] args) { // Initialise a seed value long seed = 18 ; // Create an instance of Random using the seed value Random r1 = new Random(seed); // Printing the primitive datatype-integer // by parsing using nextInt() method System.out.println(r1.nextInt()); // Create a different instance of Random using the // same seed value Random r2 = new Random(seed); // Again, printing the primitive datatype-integer // by parsing using nextInt() method System.out.println(r2.nextInt()); // Change the seed value to // some other random value seed = 34 ; // Create a new instance using the updated seed // value Random r3 = new Random(seed); // Lastly printing the primitive datatype-integer // by parsing using nextInt() method System.out.println(r3.nextInt()); } } |
-1148559096 -1148559096 -1167027043
Now dwelling onto the next class that is our ThreadLocalRandom class
ThreadLocalRandom class present inside the java.util package is also used for generating a stream of pseudo-random numbers. It is a sub-class of the Random class discussed above. As the name suggests this class generates random numbers isolated to the current thread. A ThreadLocalRandom is initialized using an internally generated seed value that is not otherwise modifiable. Using ThreadLocalRandom instead of shared instances of Random will result in low contention and overhead. ThreadLocalRandom, just like its parent class, is not cryptographically secure.
Syntax:
public class ThreadLocalRandom extends Random
Implementation: Let us take a scenario where we are creating two simple threads in the main. Inside the run() method we call the ThreadLocalRandom.current.nextInt(). Both the threads use the same value of seed i.e. 10 but give different results because the call to nextInt() is isolated by the thread execution.
Example
Java
// Java Program to Illustrate ThreadLocalRandom class // Importing ThreadLocalRandom class from utility package // named java.util.concurrent package import java.util.concurrent.ThreadLocalRandom; // Class 1 // Main class extending parent class- Thread class ThreadLocalRandomNumbers extends Thread { // Method 1 // The run() method of the Thread class // Must be defined by every class that extends it public void run() { // Try block to check for exceptions try { // Initializing a seed value to // some random integer value int seed = 10 ; // Getting the current seed by // calling over ThreadLocalRandom class and // storing it in a integer variable int r = ThreadLocalRandom.current().nextInt(seed); // Printing the generated number r // The thread id is obtained using getId() System.out.println( "Thread " + Thread.currentThread().getId() + " generated " + r); } // Catch block to catch the exceptions catch (Exception e) { // Display message on the console if // the exception/s occur System.out.println( "Exception" ); } } // Method 2 // Main driver method public static void main(String[] args) { // Create two threads ThreadLocalRandomNumbers t1 = new ThreadLocalRandomNumbers(); ThreadLocalRandomNumbers t2 = new ThreadLocalRandomNumbers(); // Starting th above created threads // using the start() method t1.start(); t2.start(); } } |
Thread 12 generated 7 Thread 11 generated 0
Now we are done with discussing both the classes and have an adequate understanding of both of them. Now wrapping up the article by concluding out the differences between them.
Random | ThreadLocalRandom |
---|---|
If different threads use the same instance of Random it results in contention and consequent performance degradation. | There is no contention because the random numbers generated are local to the current thread. |
Uses Linear Congruential Formula to modify its seed value. | The Random generator is initialized using an internally generated seed. |
Useful in applications where each thread has its own set of Random instances to use. | Useful in applications where multiple threads use random numbers in parallel in thread pools. |
This is the Parent class. | This is the Child class. |