从多个线程调用java.util.Collections.shuffle()?

时间:2016-11-28 08:59:43

标签: java concurrency

我正在做一个学校作业,我们应该将C ++程序“翻译”为Java并比较性能。该程序使用不同的执行方法(newSingleThreadExecutor和newFixedThreadPool)按顺序运行一些工作并使用不同大小的线程池。这项工作是每个线程的本地工作 - 创建随机数的ArrayList,将一些随机数写入临时文件,并对ArrayList进行混洗。

我遇到了顺序执行比并发执行更快的问题,我似乎已经确定使用java.util.Collections.shuffle(myArrayListOfIntegers)。这似乎使用java.util.Random的静态实例来重新排列列表,这似乎是导致我的问题的原因 - 如果我自己制作shuffle方法,就像上面提到的那样,但是使用了一个新的Random实例每次通话,事情都会有很大改善。

问题1。我认为静态随机实例是导致我出现问题的原因是正确的吗?

java.util.Collections.shuffle(List<?> list)方法如下所示

public static void shuffle(List<?> list) {
    Random rnd = r;
    if (rnd == null)
        r = rnd = new Random(); // harmless race.
    shuffle(list, rnd);
}

private static Random r;

问题2。上述方法中的Random rnd = r;应该做什么?它不只是复制参考?为什么不使用Random rnd = new Random()代替(这似乎解决了我的问题)?

1 个答案:

答案 0 :(得分:0)

  

问题1.假设静态随机实例导致我的问题,我是否正确?

可能不是。洗牌将是O(N)或其他什么,所以我怀疑它是你问题的根源。它确实在内部使用volatile变量来使其成为线程安全,这可能是一个问题,特别是如果存在大量的线程争用,但IO通常要贵得多。您可以尝试使用ThreadLocalRandom的本地副本,该副本不会使用volatile字段来比较它的效果。

Collections.shuffle(list, ThreadLocalRandom.current());

要弄清楚是要对您的程序进行分析器或其他分析。监视任何IO(输入,输出,日志记录等)。众所周知,Java程序很难从挂钟计算中推断性能信息,因为有很多动态优化和代码交换正在进行 - 特别是在应用程序启动时。

如果你仍然需要确信shuffle(...)不是问题,那么在你的shuffle周围放一个for循环,看它是否会显着增加你的应用程序的运行时间。

  

问题2.什么是Random rnd = r;在上面的方法应该做什么?它不仅仅是复制参考文献吗?为什么不使用Random rnd = new Random()代替(这似乎解决了我的问题)?

首先,有一个Collections.shuffle(List, Random)方法允许您设置使用您自己的本地随机。

关于为什么该方法都有本地字段rnd以及static字段r的学术问题,我想这是为了确保shuffle方法使用在方法中实例化的rnd而不是可能由另一个线程创建的那个,因为当2个线程存储到r然后使用它时存在竞争条件。如果不是那样的话我就不确定为什么代码是这样编写的。