Java ThreadLocalRandom 上的 Random
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23396033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Random over ThreadLocalRandom
提问by
Instances of java.util.Random are threadsafe. However, the concurrent use of the same java.util.Random instance across threads may encounter contention and consequent poor performance. Consider instead using ThreadLocalRandom in multithreaded designs.
java.util.Random 的实例是线程安全的。但是,跨线程并发使用同一个 java.util.Random 实例可能会遇到争用,从而导致性能不佳。考虑在多线程设计中使用 ThreadLocalRandom。
What kind of contention and thus poor performance ? Can anybody please, explain me here ? I don't know what algorithm goes inside Random and ThreadLocalRandom that makes them different.
什么样的争用因而性能不佳?任何人都可以请在这里解释一下吗?我不知道 Random 和 ThreadLocalRandom 中的什么算法使它们不同。
采纳答案by John Humphreys - w00te
This might help a little:
这可能会有所帮助:
http://thoughtfuljava.blogspot.com/2012/09/prefer-threadlocalrandom-over-random.html
http://thoughtfuljava.blogspot.com/2012/09/prefer-threadlocalrandom-over-random.html
Quoted from source:
引自来源:
Normally to generate Random numbers, we either do Create an instance of java.util.Random OR Math.random() - which internally creates an instance of java.util.Random on first invocation. However in a concurrent applications usage of above leads to contention issues
通常要生成随机数,我们要么创建 java.util.Random 的实例,要么创建 Math.random() - 它在第一次调用时在内部创建 java.util.Random 的实例。但是在并发应用程序中使用上述方法会导致争用问题
Random is thread safe for use by multiple threads. But if multiple threads use the same instance of Random, the same seed is shared by multiple threads. It leads to contention between multiple threads and so to performance degradation.
Random 是线程安全的,可供多线程使用。但是如果多个线程使用同一个 Random 实例,同一个种子就会被多个线程共享。它会导致多个线程之间发生争用,从而导致性能下降。
ThreadLocalRandom is solution to above problem. ThreadLocalRandom has a Random instance per thread and safeguards against contention.
ThreadLocalRandom 是上述问题的解决方案。ThreadLocalRandom 每个线程都有一个 Random 实例并防止争用。
So, basically, using a random instance per thread allows you to stop synchronizing on the seed which must be used by all threads.
因此,基本上,每个线程使用一个随机实例允许您停止同步所有线程必须使用的种子。
回答by nils
Well, if you use the same data structure over multiple threads it has usually to be synchronized. This is expensive and needs time. A ThreadLocalRandom does not have to be synchronized as it is only used by one thread.
好吧,如果您在多个线程上使用相同的数据结构,它通常必须同步。这是昂贵的并且需要时间。ThreadLocalRandom 不必同步,因为它仅由一个线程使用。
回答by Mani
From ThreadLocalRandom API Document
来自 ThreadLocalRandom API 文档
A random number generator isolated to the current thread. Like the
* global {@link java.util.Random} generator used by the {@link
* java.lang.Math} class, a {@code ThreadLocalRandom} is initialized
* with an internally generated seed that may not otherwise be
* modified. When applicable, use of {@code ThreadLocalRandom} rather
* than shared {@code Random} objects in concurrent programs will
* typically encounter much less overhead and contention. Use of
* {@code ThreadLocalRandom} is particularly appropriate when multiple
* tasks (for example, each a {@link ForkJoinTask}) use random numbers
* in parallel in thread pools.
Random can be created multiple times / same Random Object would shared across multiple threads ( due to the fact safe to use) . How ever creating multiple instance / same resource access by multiple thread would cause overhead.
Random 可以多次创建/相同的 Random 对象将在多个线程之间共享(由于使用安全的事实)。如何通过多个线程创建多个实例/相同的资源访问会导致开销。
Instead of Creating instance per Thread and maintain the resource in ThreadLocal would be more perfect. since the instance is not shared across multiple Threads. and there are no public constructor , your should use the factory method to get it.
而不是每个线程创建实例并在 ThreadLocal 中维护资源会更完美。因为实例不是跨多个线程共享的。并且没有公共构造函数,您应该使用工厂方法来获取它。
I would say, it is just Factory of Random Objects which maintains /caches instance per thread.
我会说,它只是一个随机对象工厂,它为每个线程维护 /caches 实例。
回答by cybersam
A Random instance can only provide a random number to one thread at a time. So, if you have many threads simultaneously requesting random numbers from that instance, that tends to slow down all the threads.
Random 实例一次只能向一个线程提供一个随机数。因此,如果您有多个线程同时从该实例请求随机数,则往往会减慢所有线程的速度。
On the other hand, each thread would have its own ThreadLocalRandom instance, so no threads would be blocked when requesting a random number.
另一方面,每个线程都有自己的 ThreadLocalRandom 实例,因此在请求随机数时不会阻塞线程。
回答by user1676075
The core algorithms are essentially the same. The ThreadLocalRandom uses the Java ThreadLocal construct to create a new Random variable for each thread. This guarantees that the calls from each thread will never conflict with each (no contention).
核心算法基本相同。ThreadLocalRandom 使用 Java ThreadLocal 构造为每个线程创建一个新的 Random 变量。这保证了来自每个线程的调用永远不会与每个线程发生冲突(无争用)。
Take a look at this line from Random for comparison:
看看 Random 的这一行进行比较:
} while (!seed.compareAndSet(oldseed, nextseed));
When you ask for a next value, Random takes the old value and generates a new value. It then uses the AtomicLong.compareAndSet function to set the new value, only if the old value is still the one it used. If another thread had changed the value, the loop will run again (and again, until it's the only loop that's both get and set the value in one random number generation). Thus there is possible contention, and thus possible performance implications.
当您要求下一个值时,Random 会采用旧值并生成一个新值。然后它使用 AtomicLong.compareAndSet 函数设置新值,前提是旧值仍然是它使用的值。如果另一个线程更改了该值,则该循环将再次运行(并且再次运行,直到它成为在一个随机数生成中同时获取和设置该值的唯一循环)。因此可能存在争用,从而可能影响性能。
The ThreadLocalRandom, because it is guaranteed not to conflict, does not require atomic functions and thread-safe operations/locking.
ThreadLocalRandom 因为保证不冲突,所以不需要原子函数和线程安全操作/锁定。
There are some tradeoffs you would want to think about. Using one Random allows for one random number generator which is very useful if you want to use a single seed for your application. If you make only occasional calls to Random, so that conflicts are likely to be "rare" (not the normal case) then you might not worry about conflicts and the small individual impact to performance may not matter. If you're calling random hundreds of time per seconds across multiple threads, then you clearly want to use ThreadLocalRandom.
您需要考虑一些权衡。使用一个 Random 允许使用一个随机数生成器,如果您想为应用程序使用单个种子,这将非常有用。如果您只是偶尔调用 Random,因此冲突可能是“罕见的”(不是正常情况),那么您可能不会担心冲突,并且对性能的微小个人影响可能无关紧要。如果您在多个线程中每秒调用 random 数百次,那么您显然想使用 ThreadLocalRandom。
回答by Mostowski Collapse
There are some problems with ThreadLocalRandom, that you cannot control the initial seed. I also don't find a working set seed method somewhere.
ThreadLocalRandom 存在一些问题,您无法控制初始种子。我也没有在某处找到工作集种子方法。
It should be noted that there is contention when multiple threads use Math.random(), since they will under the hood access a shared instance of the class Random, there is an alternative in using ThreadLocalRandom which also solves the seed problem.
应该注意的是,当多个线程使用 Math.random() 时存在争用,因为它们将在引擎盖下访问类 Random 的共享实例,因此使用 ThreadLocalRandom 有一个替代方案,它也解决了种子问题。
ThreadLocalRandom uses a seed stashed into the Thread. And they decided to do the initial seed for you, without any means to control it. You can equally well create your own instance of Random and use it in a thread local fashion. So if you do the following:
ThreadLocalRandom 使用隐藏在线程中的种子。他们决定为你做最初的种子,没有任何办法控制它。您同样可以创建自己的 Random 实例并以线程本地方式使用它。因此,如果您执行以下操作:
/* my thread */
rnd = new Random(my_seed);
/* use rnd */
You will also see no contention. And using the same seed, you get reproducablerandom sequences, which can help in testing. When you have multiple threads you can distribute seeds over these threads. There should be algorithms around to generate good distance seeds.
您还将看到没有争用。使用相同的种子,您可以获得可重复的随机序列,这有助于测试。当您有多个线程时,您可以在这些线程上分发种子。周围应该有算法来生成良好的距离种子。