18

我正在寻找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

4 回答 4

9

您可以简单地使用Random,只需确保每个Random对象只能在单个线程中访问。

Random, 作为一个古老的类Vector, 是不必要的大量同步。他们可能想炫耀 Java 的线程支持,因为这在当时很重要。此外,Java 主要用于在大多数具有单处理器的消费类 PC 上运行,因此同步不会像今天在多处理器上那样影响扩展。

现在一个明显的答案是提供一个线程不安全的版本Random,就像提供线程不安全版本ArrayList作为Vector. 这并没有发生,相反,我们得到了ThreadLocalRandom. 这有点奇怪,不知道背后的动机是什么。在 java8 中,ThreadLocalRandom被进一步优化为直接对Thread对象中的一些 int 字段进行操作。

于 2013-04-02T14:54:55.857 回答
1

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

于 2013-04-02T13:33:40.867 回答
0

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

于 2013-11-29T16:13:59.683 回答
0

取决于所需种子的性质,ThreadLocalRandom 不允许设置随机种子。在某些情况下,您可能希望通过当前请求中的“用户”来播种 Random,因此“随机性对于用户来说是一致的”,并且由于容器为新请求重用线程(很少)并且 new 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 慢。

于 2021-07-30T22:53:48.550 回答