javamultithreadingperformancerandomsecure-random

Reusing java.util.Random instance vs creating a new instance every time


The title pretty much summarizes it - we can create one instance of java.util.Random (or SecureRandom) and use it every time we need a random value or we can create a new instance every time on demand. Wondering which one is the preferred way and why?

To give some idea about the context: the random value is being generated inside an HTTP request handler, one per request, and I'm looking for the best combination for security and performance considering multi-threading.


Solution

  • It depends.

    Creating a single instance is obviously simpler and should be the default behaviour. Both Random and SecureRandom are threadsafe, and will therefore work just fine. First do the simple and correct thing that works, then measure your performance against your expected peak contention / peak perf budget, and analyze the results.

    Random

    If you're using Random and the single instance approach is too slow, consider using ThreadLocalRandom if possible. The JavaDoc in Random suggests its usage nicely:

    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.

    It will only create an instance for each thread accessing it. The creation cost of a Random / ThreadLocalRandom instance is not insane, but it is higher than the creation of a "normal" object, so you should probably avoid creating a new instance for each incoming request. Creating one per thread is generally a nice sweet spot.

    I would say that in modern applications with pooled threads, you should almost always use ThreadLocalRandom instead of Random - the randomness is the same, but the single-thread performance is much better.

    SecureRandom

    If you're using SecureRandom, though, ThreadLocalRandom is not an option. Again, do not guess, measure! Maybe using a single shared instance of a SecureRandom will be good enough. Test with your expected peak contention, and if the secure random instance turns out to be a bottleneck, only then think about ways to improve the situation.

    Creating a SecureRandom instance is very costly, so you absolutely do not want to create one for each incoming request.

    Depending on your application, a ThreadLocal<SecureRandom> may be an option. Still, I think that's an overkill, and a scheme similar to the Striped class (with X SecureRandom instances created and accessed randomly to help prevent contention) may be preferred.