Java中的并发随机数生成

时间:2016-01-02 15:11:55

标签: java multithreading random

在Web服务器上,许多线程正在向客户端提供内容。 A / B测试在网站上进行,因此我们需要PRNG为每个会话和测试选择一个变体。 显然,当使用PRNG的单个实例时,它会被同时访问,因此可能需要适当的锁定或其他机制。

最初我们使用了java.util.Random(juR),但由于它有提到的缺陷,例如How good is java.util.Random,我们尝试使用MersenneTwister。 但是,由于Mersenne-Twister relies on an internal state这一事实导致性能大幅下降,因此需要同步访问nextInt()。 另一种选择可能是XOR换档PRNG,但它与Mersenne Twister有同样的问题。 您可以找到解释,例如在这里:http://xorshift.di.unimi.it/

Random uses a compareAndSet操作,由于它不需要锁定,因此似乎要快得多,但根据类Javadoc,它仍然不是线程安全的。相反,建议使用ThreadLocalRandom代替,这基本上会产生一个PRNG池。根据请求,随机可用线程处理HTTPS请求,因此从一组可用PRNG中选择随机PRNG。显然这很快。

来自这样一个池的随机数是否与单个PRNG实例中的随机数一样好?

另一种方法是使用单个PRNG实例从其预先生成值流,例如使用ArrayBlockingQueue

哪种解决方案在性能方面更有效?

2 个答案:

答案 0 :(得分:3)

您可以通过BlockingQueue

传递结果,使任何随机数生成器线程安全
class SafeRandom implements Runnable {

    Random r = new Random();
    BlockingQueue<Double> q = new ArrayBlockingQueue<>(10);

    double get() throws InterruptedException {
        return q.take();
    }

    @Override
    public void run() {
        try {
            while (true) {
                q.put(r.nextDouble());
            }
        } catch (InterruptedException ie) {
        }
    }

}

答案 1 :(得分:2)

为避免同步问题,每个线程都有一个RNG。为了避免线程特定的RNG给出相同的输出,让主RNG为线程特定的RNG生成一系列初始种子。这可能需要将额外的种子参数传递到您的代码中以生成新线程。

您需要自己测试一下RNG的不同选项在您的工具包上的运行速度。如果需要,可以将不同的RNG引擎用于主RNG和线程特定的RNG。通常选择具有线程特定RNG的快速建立时间的RNG。这对主RNG来说并不重要,因为它只设置一次。