我应该更喜欢ThreadLocalRandom而不是ThreadLocal <random>?</random>

时间:2013-04-02 13:28:49

标签: java random concurrency

我希望在多个线程中使用(种子)Random个对象,而javadocs指向我ThreadLocalRandom看起来很棒,除非我无法设置种子,所以我无法确保不同线程或运行之间的一致性。是否有任何实际的理由使用ThreadLocalRandom或者可以接受以下内容:

// Pass returned ThreadLocal object to all threads which need it
public static ThreadLocal<Random> threadRandom(final long seed) {
    return new ThreadLocal<Random>(){
        @Override
        protected Random initialValue() {
            return new Random(seed);
        }
    };
}

4 个答案:

答案 0 :(得分:7)

您只需使用Random,只需确保每个Random对象只能在一个帖子中访问。

Random,像Vector这样的古老阶级,不必要地高度同步。他们可能想展示Java的线程支持,因为那时它是一个大问题。此外,Java主要用于在主要具有单个处理器的消费者PC上运行,因此同步不会像现在多处理器那样影响扩展。

现在一个明显的答案是提供Random的线程不安全版本,就像提供thread-unsfae ArrayList作为Vector的替代版本一样。这没有发生,相反,我们得到了ThreadLocalRandom。这有点奇怪,不确定背后的动机是什么。在java8中,ThreadLocalRandom进一步优化,直接在Thread对象的某些int字段上运行。

答案 1 :(得分:1)

code for ThreadLocalRandom似乎无论如何都被实现为ThreadLocal(不完全像你所说的那样,但可能足够接近)。我认为你所拥有的将会很有效。

答案 2 :(得分:0)

首先,您的代码为每个线程使用相同的种子。这可能是一个安全问题。 此外,对Random实例的成员的每次访问都是同步的,因此它将比ThreadLocalRandom的相应方法(未同步)慢。 如果编译器可以确定,您的Random实例不会逃避当前的Thread,它可以优化那些“同步”。但由于您可以在ThreadLocal中存储共享引用,因此编译器无法检查它。

答案 3 :(得分:0)

取决于所需种子的性质,ThreadLocalRandom 不允许设置随机种子。在某些情况下,您可能希望通过当前请求中的“用户”为 Random 提供种子,因此“随机性对于用户来说是一致的”,并且因为容器为新请求和新 Random 重用线程(很少) () 是昂贵的,您可能想要创建自己的 ThreadLocal。由于 Java ThreadLocalRandom 不支持种子,因此您可以在 JDK 1.8 中轻松编写:

public class RandomUtil {

 private static final ThreadLocal<Random> RANDOM_THREAD_LOCAL = ThreadLocal.withInitial(Random::new);

 public static Random threadLocalRandom(long seed){
    Random random = RANDOM_THREAD_LOCAL.get();
    random.setSeed(seed);
    return random;
}

由于每个 Random 对线程来说都是局部的并且是线程安全的,因此可以“如果需要”为下一个请求/用户重新播种,而无需创建新的 Random()。这应该比为每个请求创建 new Random(user seed) 性能好,但比具有内部优化的 Java ThreadLocalRandom 慢。