Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 234
khachik Avatar asked Oct 16 '18 15:10

khachik


2 Answers

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.

like image 153
Petr Janeček Avatar answered Oct 19 '22 20:10

Petr Janeček


If you need random numbers for information security, only a cryptographic RNG (such as java.security.SecureRandom) will do. And for any cryptographic RNG, the simplest approach is to use only one thread-safe instance of it for the entire application to use (note that SecureRandom is thread-safe according to the documentation); there is generally no benefit to creating multiple instances of a cryptographic RNG, as they will all eventually have to be initialized with high-entropy ("unpredictable") data.

Gathering such "unpredictable" data is not trivial, and at least for your application, you need not worry about that when you use SecureRandom, which largely does this for you and includes a setSeed method you can use to add extra data to supplement its randomness.

like image 27
Peter O. Avatar answered Oct 19 '22 18:10

Peter O.