我希望在多个线程中使用(种子)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);
}
};
}
答案 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 慢。