gpt4 book ai didi

java - 从 Java 8 开始有什么理由写 `new Random()` 吗?

转载 作者:IT老高 更新时间:2023-10-28 21:13:15 26 4
gpt4 key购买 nike

出于某种原因,我曾经认为 java.util.Random 是线程不安全的,例如 HashMapBitSet,并且Math.random() 被实现为使用 synchronized block 包装对 Random 的访问,或 ThreadLocalRandom.current().nextDouble( ).

其实java.util.Random is thread-safe (通过原子)。因此,要点:即使我需要在单个线程中进行一些随机输入,使用 ThreadLocalRandom 也是有意义的,因为内部没有原子读写,编译为锁定指令并发出内存屏障。

此外,由于Java 8,ThreadLocalRandom本质上是一个单例,它的状态保存在java.lang.Thread类的一些字段中。因此方法 ThreadLocalRandom.current() 不是对 ThreadLocalMap 的访问,而只是一个静态字段读取,即。 e.很便宜。

我有两个问题:

  1. 从计算机科学的角度来看,是几个线性同余随机生成器的输出(以 ThreadLocalRandom 的方式初始化)与单个线性同余的输出相同“随机”随机生成器(java.util.Random 实例)?

  2. 如果第一个问题的答案是肯定的,是否有任何理由编写构造 new Random()(无种子)而不是 ThreadLocalRandom.current()曾经?

更新。我认为像 ThreadLocalRandom.current().ints().parallel().collect(...) 这样的调用可能不正确,因为线程的随机生成器状态可能未在 ForkJoinPool 中初始化 工作线程,但似乎 ThreadLocalRandom 覆盖了方法 ints()longs()doubles(),使上述构造正确。

最佳答案

1...

这取决于实现,但对于 Java,它会是 same 没有那么糟糕,因为 Java 有一个 static unique seed atomic long that is manipulated everytime随机创建。但是,我不会对其他语言或实现感到惊讶,但事实并非如此,它们可能只使用系统时间(Java 也使用系统时间,但组合使用了唯一种子)。那是在某些系统上,您可以为多个线程获得相同的种子。

经过进一步检查和一些实际测试(尽管是脆弱的测试),看来我之前可能错了,因为在同时(即使它们是不同的实例)。我不完全确定它的种子冲突或实际的全局种子增量是否可以预测的事实。当然,这可能只是我的测试工具或方法。

根据维基百科:

Random number generators, particularly for parallel computers, should not be trusted.[12] It is strongly recommended to check the results of simulation with more than one RNG to check if bias is introduced. Among the recommended generators for use on a parallel computer include combined linear congruential generators using sequence splitting and lagged Fibonacci generators using independent sequences.

所以理论上它应该更好,因为 ThreadLocalRandom 会创建独立的序列,所以我的测试可能有缺陷。

这当然是基于伪随机的。

物理随机性或基于实际熵的安全随机生成器可能会导致差异(即更多/更少的熵),但我不是专家,也无权使用。

2...

我无法提出一个特定的用例,但一个可能是您使用 ExecutorService 不断创建和处理线程(假设他们无法控制)但一次不会很多(即最多 2并发线程)。您可能会发现 ThreadLocalRandom 比创建单个共享 Random 更昂贵。

考虑到您的评论,另一个可能更好的原因是您可能想要重置所有进程的种子。如果您有一个使用线程的游戏(不是很多,但让我们假装),您可能希望全局重置种子以进行测试,这比尝试将消息传递给所有正在运行的线程更容易使用 AtomicReference 到 Random。

您可能不想使用 ThreadLocalRandom 的另一个原因是平台原因。一些平台对线程创建和线程本地创建有特定要求。因此,要解决“你有一个比随机数更大的问题”,请查看 Google Apps其中:

A Java application can create a new thread, but there are some restrictions on how to do it. These threads can't "outlive" the request that creates them. (On a backend server, an application can spawn a background thread, a thread that can "outlive" the request that creates it.)

为了解决您对为什么要使用不能重用线程的 ExecutorService 的附加评论:

or use the factory object returned by com.google.appengine.api.ThreadManager.currentRequestThreadFactory() with an ExecutorService (e.g., call Executors.newCachedThreadPool(factory)).

即不一定重用线程的线程池。

关于java - 从 Java 8 开始有什么理由写 `new Random()` 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29698704/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com