我正在做一个学校作业,我们应该将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()
代替(这似乎解决了我的问题)?
答案 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
然后使用它时存在竞争条件。如果不是那样的话我就不确定为什么代码是这样编写的。