简体   繁体   中英

Java Configuring random number generators in multi-threaded environment

I have an application which uses pseudo-random numbers. While I'm testing the application, I want reproducibility, which I arrange by using a seed for the random number generator. Currently, the RNG is declared inside the class that uses it as a static variable: private static Random rng = new Random(seed) . I have a few questions.

  1. Given that I want to seed the RNG for reproducibility, does it make sense to declare the variable static ?
  2. I may need to add more different classes which need random numbers. Should I move the RNG to a separate class so I can still use one seed for the whole application? If so, should I use a static Random or a singleton object?
  3. What happens if I decide to use random numbers in multiple threads? It seems that if I use a strategy like 2., I might still lose predictability, as I can't say for sure the order in which the threads are going to access the RNG. The RNG will still generate the same, predictable sequence of random numbers, but from one run of the program to another, the thread which grabs the first (or nth) random number in the sequence may differ.
  4. What this indicates to me is that each thread needs its own RNG in order for results to be reproducible across all runs. Does that mean that each thread needs its own seed? If so, would that guarantee reproducibility, or is there something else I need to do to eliminate the randomness that may be introduced by having multiple threads?
  5. Is there a way to generate seeds from a single number which minimizes the correlation between the different RNGs?

In other words, if thread 0 has Random thread0RNG = new Random(seed) and thread 1 has Random thread1RNG = new Random(seed) , I would only need one seed, but the random numbers in each thread would be highly correlated. I could have two seeds, but then I couldn't associate a run of the program with a single number, passed on the command line, say. Would it be possible and appropriate to say seed0 = someFunction(seed,0) and seed1 = someFunction(seed,1) ?

Yes, you should give each thread its own Random object to avoid unreproducable interleaving due to thread timing.

You can all seed them with the same number, but then they will all get the exact same sequence of numbers. I don't know if that's a problem.

If it is a problem, you can have one "master" Random object to generate the seeds for the other ones. Every time you create a new thread, get the seed from the master. But you have to make sure that you create all the threads (or at least retrieve the seeds) in the same order every time.

First of all, Random is thread-safe, so you can safely use it across multiple threads, although due to locking, having one single Random instance might result in poor performance. To avoid this, use ThreadLocalRandom instead.

But this is no solution, if predicatability is required as in your case. Having one single shared RNG in a concurrent environment will never be predictable. Hence you are right, you'll need one instance per thread , and every instance will have to be initialized with a seed.

But if all RNG instances use the same seed, the resulting random sequences will not only be highly correlated, they will be identical! So you'll have to use different seeds for all RNGs

So I suggest to use a central RNG to generate the seeds for all other RNGs. But note that this is only predictable, if the order in which the RNGs are seeded is well defined - again this might not be straight forward in a concurrent environment, but doable.

Use a RNG for each thread, for example with ThreadLocalRandom . Multithreading doesn't affect randomness, if each thread have their own generator. The choice of seed is up to you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM