在ThreadLocalRandom上随机
java.util.Random的实例是线程安全的。 但是,跨线程并发使用相同的java.util.Random实例可能会遇到争用,从而导致性能不佳。 请考虑在multithreading设计中使用ThreadLocalRandom。
什么样的争用,从而表现不佳? 有人可以,在这里解释一下吗? 我不知道Random和ThreadLocalRandom里面的算法是什么让它们与众不同。
这可能有点帮助:
http://thoughtfuljava.blogspot.com/2012/09/prefer-threadlocalrandom-over-random.html
引自来源:
通常要生成随机数,我们要么创建一个java.util.Random或Math.random()的实例 – 它在第一次调用时在内部创建java.util.Random的实例。 但是,在并发应用程序中,上述使用会导致争用问题
Random是线程安全的,可供多个线程使用。 但是如果多个线程使用相同的Random实例,则多个线程共享相同的种子。 它会导致多个线程之间的争用,从而导致性能下降。
ThreadLocalRandom是上述问题的解决方案。 ThreadLocalRandom每个线程都有一个Random实例,可以防止争用。
因此,基本上,每个线程使用一个随机实例允许您停止同步所有线程必须使用的种子。
ThreadLocalRandom存在一些问题,您无法控制初始种子。 我也找不到某个工作集种子方法。
应该注意的是,当多个线程使用Math.random()时存在争用,因为它们将在底层访问Random类的共享实例,使用ThreadLocalRandom还可以解决种子问题。
ThreadLocalRandom使用存储在Thread中的种子。 他们决定为你做初始种子,没有办法控制它。 您也可以创建自己的Random实例,并以线程本地方式使用它。 因此,如果您执行以下操作:
/* my thread */ rnd = new Random(my_seed); /* use rnd */
您也将看不到争用。 使用相同的种子,您可以获得可重复的随机序列,这有助于测试。 当您有多个线程时,您可以通过这些线程分发种子。 应该有算法来生成良好的距离种子。
核心算法基本相同。 ThreadLocalRandom使用Java ThreadLocal构造为每个线程创建一个新的Random变量。 这保证了每个线程的调用永远不会与每个线程冲突(没有争用)。
看看Random的这一行进行比较:
} while (!seed.compareAndSet(oldseed, nextseed));
当您要求下一个值时,Random将获取旧值并生成新值。 然后它使用AtomicLong.compareAndSet函数来设置新值,仅当旧值仍然是它使用的值时。 如果另一个线程更改了该值,则循环将再次运行(并且再次运行,直到它是唯一的循环,并且在一个随机数生成中设置该值)。 因此可能存在争用,从而可能产生性能影响。
ThreadLocalRandom因为保证不会冲突,所以不需要primefaces函数和线程安全操作/锁定。
你需要考虑一些权衡。 使用一个随机允许一个随机数生成器,如果您想为您的应用程序使用单个种子,这非常有用。 如果您只是偶尔拨打随机电话,那么冲突很可能是“罕见的”(不是正常情况),那么您可能不会担心冲突,个人对性能的影响可能无关紧要。 如果你在多个线程中每秒调用几百个随机时间,那么你显然想要使用ThreadLocalRandom。
好吧,如果你在多个线程上使用相同的数据结构,它通常是同步的。 这很昂贵,需要时间。 ThreadLocalRandom不必同步,因为它仅由一个线程使用。
来自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.
随机可以多次创建/相同的随机对象将在多个线程之间共享(由于使用安全的事实)。 如何通过多个线程创建多个实例/相同资源访问会导致开销。
而不是创建每个线程的实例并在ThreadLocal中维护资源将更完美。 因为实例不是跨多个线程共享的。 并且没有公共构造函数,您应该使用工厂方法来获取它。
我会说,它只是随机对象的工厂,它维护/缓存每个线程的实例。
Random实例一次只能为一个线程提供一个随机数。 因此,如果您有多个线程同时从该实例请求随机数,则往往会减慢所有线程的速度。
另一方面,每个线程都有自己的ThreadLocalRandom实例,因此在请求随机数时不会阻塞任何线程。