关于Java:随机类线程安全吗?

Is Random class thread safe?

在多个线程之间共享Random类的一个实例是否有效?特别是从多线程调用nextInt(int)


从某种意义上说,它是线程安全的,当多个线程使用时,它仍然会生成随机数。

Sun/OracleJVM实现使用synchronized和atomiclong-as-seed来提高线程间的一致性。但文档中的所有平台似乎都不能保证这一点。

我不会写你的程序要求这样的保证,特别是当你不能确定调用nextInt()的顺序时。


它是线程安全的,尽管它并不总是。

请参阅http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6362070了解更多详细信息。


根据文档,math.random()保证多线程使用它是安全的。但随机类没有。我假设你必须自己同步。


是的,随机是线程安全的。nextInt()方法调用受保护的next(int)方法,该方法使用AtomicLong seed, nextseed生成下一个种子。AtomicLong用于种子生成时的线程安全。


如前所述,它是线程节省,但根据本文(link dead),使用java.util.concurrent.ThreadLocalRandom可能是明智的。ThreadLocalRandom也是Random的一个子类,因此它是向后兼容的。

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


没有理由多个线程不能全部使用相同的随机对象。但是,由于类不是显式线程安全的,并且通过种子维护一个伪随机数序列。多个线程可能以相同的随机数结束。最好为每个线程创建多个Random,并以不同的方式对其进行种子设定。

编辑:我刚刚注意到Sun实现使用Atomiclong,所以我想这是线程安全的(正如Peter Lawrey(+1))。

edit2:openjdk还使用atomiclong作为种子。正如其他人所说,尽管依靠这一点仍然不好。


下面是我如何在不假设随机变量使用原子变量的情况下处理这个问题。如果currentTime * thread id在未来的某个时候是相等的,它仍然可以随机碰撞,但这对于我的需要来说已经足够罕见了。为了真正避免冲突的可能性,您可以让每个请求等待一个唯一的时钟时间戳。

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * 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());
    }
};


没有为一个实例设置Random类,以便在多个线程中使用。当然,如果你这样做,你很可能会增加不可预测和接近随机数的可能性。但由于它是一个伪随机生成器,我不明白为什么需要共享一个实例。是否有更具体的要求?