Random over ThreadLocalRandom

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.

What kind of contention and thus poor performance ? Can anybody please, explain me here ? I don't know what algorithm goes inside Random and ThreadLocalRandom that makes them different.


Solution 1:

This might help a little:

http://thoughtfuljava.blogspot.com/2012/09/prefer-threadlocalrandom-over-random.html


Quoted from source:

Normally to generate random numbers, we either do create an instance of java.util.Random or Math.random() - which internally creates an instance of java.util.Random on first invocation. However, in a concurrent applications usage of above leads to contention issues.

Random is thread safe for use by multiple threads. But if multiple threads use the same instance of Random, the same seed is shared by multiple threads. It leads to contention between multiple threads and so to performance degradation.

ThreadLocalRandom is solution to above problem. ThreadLocalRandom has a Random instance per thread and safeguards against contention.


So, basically, using a random instance per thread allows you to stop synchronizing on the seed which must be used by all threads.

Solution 2:

There are some problems with ThreadLocalRandom, that you cannot control the initial seed. I also don't find a working set seed method somewhere.

It should be noted that there is contention when multiple threads use Math.random(), since they will under the hood access a shared instance of the class Random, there is an alternative in using ThreadLocalRandom which also solves the seed problem.

ThreadLocalRandom uses a seed stashed into the Thread. And they decided to do the initial seed for you, without any means to control it. You can equally well create your own instance of Random and use it in a thread local fashion. So if you do the following:

/* my thread */
rnd = new Random(my_seed);
/* use rnd */

You will also see no contention. And using the same seed, you get reproducable random sequences, which can help in testing. When you have multiple threads you can distribute seeds over these threads. There should be algorithms around to generate good distance seeds.

Solution 3:

The core algorithms are essentially the same. The ThreadLocalRandom uses the Java ThreadLocal construct to create a new Random variable for each thread. This guarantees that the calls from each thread will never conflict with each (no contention).

Take a look at this line from Random for comparison:

  } while (!seed.compareAndSet(oldseed, nextseed));

When you ask for a next value, Random takes the old value and generates a new value. It then uses the AtomicLong.compareAndSet function to set the new value, only if the old value is still the one it used. If another thread had changed the value, the loop will run again (and again, until it's the only loop that's both get and set the value in one random number generation). Thus there is possible contention, and thus possible performance implications.

The ThreadLocalRandom, because it is guaranteed not to conflict, does not require atomic functions and thread-safe operations/locking.

There are some tradeoffs you would want to think about. Using one Random allows for one random number generator which is very useful if you want to use a single seed for your application. If you make only occasional calls to Random, so that conflicts are likely to be "rare" (not the normal case) then you might not worry about conflicts and the small individual impact to performance may not matter. If you're calling random hundreds of time per seconds across multiple threads, then you clearly want to use ThreadLocalRandom.

Solution 4:

Well, if you use the same data structure over multiple threads it has usually to be synchronized. This is expensive and needs time. A ThreadLocalRandom does not have to be synchronized as it is only used by one thread.