9

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.

informatik01
  • 16,038
  • 10
  • 74
  • 104
khachik
  • 28,112
  • 9
  • 59
  • 94
  • 1
    https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadLocalRandom.html – DodgyCodeException Oct 16 '18 at 15:09
  • There is no such thing as a "random number." Any time you see the word, "random," think "unpredictable." A number, all by itself, can't be unpredictable. What would that even mean?. A `java.util.Random` instance isn't a thing that gives you isolated random numbers: It's a thing that gives you an unpredictable _sequence_ of numbers. – Solomon Slow Oct 16 '18 at 17:46

2 Answers2

9

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.

Petr Janeček
  • 37,768
  • 12
  • 121
  • 145
2

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.

Peter O.
  • 32,158
  • 14
  • 82
  • 96