Is Random class thread safe?

2019-01-22 04:54发布

问题:

Is it valid to share one instance of the Random class between multiple threads? And to call nextInt(int) from multiple threads in particular?

回答1:

It is thread safe in the sense it will still generate random numbers when used by multiple threads.

The Sun/Oracle JVM implementation uses synchronized and AtomicLong as seed to improve consistency across threads. But it doesn't appear to be guarenteed across all platforms in the documentation.

I wouldn't write your program to require such a guarantee, especially as you cannot determine the order in which nextInt() will be called.



回答2:

It is thread safe, although it wasn't always.

See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070 for more details.



回答3:

Acording to the documentation, Math.random() guarantees it's safe for use by multiple threads. But the Random class does not. I would assume then you'll have to synchronize that yourself.



回答4:

Yes, Random is thread safe. the nextInt() method calls the protected next(int) method which uses AtomicLong seed, nextseed (atomic long) to generate a next seed. AtomicLong is used for thread-safety upon seed generation.



回答5:

As said, it is thread save, but it may be wise to use java.util.concurrent.ThreadLocalRandom according to this article (link dead). ThreadLocalRandom is also a subclass of Random, so it is backwards compatible.

The article linked compared profiling results of the different Random classes: java.util.Random, java.util.concurrent.ThreadLocalRandom and java.lang.ThreadLocal<java.util.Random>. The results showed, that the usage of ThreadLocalRandom is most performant, followed by ThreadLocal and worst performing Random itself.



回答6:

There's no reason multiple threads can't all use the same Random. However, since the class is not explicitly thread-safe and maintains a sequence of pseudo-random numbers via the seed. Multiple threads may end up with the same random number. It would be better to create multiple Randoms for each thread and seed them differently.

EDIT: I've just noticed that the Sun implementation uses AtomicLong so i guess that is Thread-safe (as also noted by Peter Lawrey (+1)).

EDIT2: OpenJDK also uses AtomicLong for the seed. As others have said though it's still not good to rely on this.



回答7:

Here's how I dealt with the problem without assuming that Random uses atomic variables. It can still randomly collide if currentTime * thread id is equal some time in the future, but that's rare enough for my needs. To truly avoid the possibility of collisions, you could have each request wait for a unique clock timestamp.

/**
 * Thread-specific random number generators. Each is seeded with the thread
 * ID, so the sequence of pseudo-random numbers are unique between threads.
 */
private static ThreadLocal<Random> random = new ThreadLocal<Random>() {
    @Override
    protected Random initialValue() {
        return new Random(
            System.currentTimeMillis() *
            Thread.currentThread().getId());
    }
};


回答8:

The Random class is not set up for one instance to be used in multiple threads. Ofcourse, if you did this, likely you will increase the possibility of getting un-predictable and closer to random numbers. But since it is a pseudo-random generator, I cannot see why you would need to share an instance. Is there a more specific requirement?