为什么 Collections#shuffle 不使用 ThreadLocalRandom?

Jac*_* G. 5 java random collections shuffle

public static void shuffle(List<?> list) {\n    Random rnd = r;\n    if (rnd == null)\n        r = rnd = new Random(); // harmless race.\n    shuffle(list, rnd);\n}\n\nprivate static Random r;\n
Run Code Online (Sandbox Code Playgroud)\n\n

我注意到Collections#shuffle使用new Random()而不是ThreadLocalRandom.current(),我很好奇为什么。我编写了一个基准测试来比较两者,并且使用的方法ThreadLocalRandom.current()每次迭代都更快。这是基准:

\n\n
@State(Scope.Benchmark)\n@BenchmarkMode(Mode.AverageTime)\n@OutputTimeUnit(TimeUnit.NANOSECONDS)\n@Warmup(iterations = 15, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n@Measurement(iterations = 20, time = 500, timeUnit = TimeUnit.MILLISECONDS)\n@Fork(5)\npublic class MyBenchmark {\n    @Param({"10", "1000", "100000"})\n    private int i;\n\n    private List<Integer> list;\n\n    private static final Random RANDOM = new Random();\n\n    @Setup\n    public void initialize() {\n        list = ThreadLocalRandom.current()\n                                .ints(i)\n                                .boxed()\n                                .collect(Collectors.toList());\n    }\n\n    public static void main(String[] args) throws Exception {\n        org.openjdk.jmh.Main.main(args);\n    }\n\n    @Benchmark\n    public List<Integer> oldMethod() {\n        Collections.shuffle(list, RANDOM);\n        return list;\n    }\n\n    @Benchmark\n    public List<Integer> newMethod() {\n        Collections.shuffle(list, ThreadLocalRandom.current());\n        return list;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:

\n\n
Benchmark                 (i)  Mode  Cnt        Score       Error  Units\nMyBenchmark.newMethod      10  avgt  100       60.802 \xc2\xb1     0.785  ns/op\nMyBenchmark.newMethod    1000  avgt  100     6879.496 \xc2\xb1    15.638  ns/op\nMyBenchmark.newMethod  100000  avgt  100  1248858.889 \xc2\xb1 33632.559  ns/op\nMyBenchmark.oldMethod      10  avgt  100       90.636 \xc2\xb1     1.379  ns/op\nMyBenchmark.oldMethod    1000  avgt  100     9740.442 \xc2\xb1    57.373  ns/op\nMyBenchmark.oldMethod  100000  avgt  100  1511428.034 \xc2\xb1 27744.775  ns/op\n
Run Code Online (Sandbox Code Playgroud)\n\n

那么,为什么new Random()使用 over呢ThreadLocalRandom.current()

\n\n

我的猜测:

\n\n
    \n
  • ThreadLocalRandom该方法自JDK 1.7发布以来就没有更新过
  • \n
  • new Random()用于线程安全?
  • \n
\n

Stu*_*rks 3

和方法是在 JDK 1.2 中添加的,而该类直到 Java 7 才添加Collections.shuffle(List)。因此,对于 Java 7 之前的所有版本,都使用.Collections.shuffle(List, Random)ThreadLocalRandomshuffle(List)Random

尽管未指定 的随机源shuffle(List),但将其更改为使用不同的随机源可能会导致行为发生意外变化。因此,该方法保持原样,使用 的实例Random

没有太大必要改变它。其他随机源(例如ThreadLocalRandomSecureRandom)是 的子类,如果应用程序需要的话,Random它们可以用于使用两个参数重载进行洗牌。shuffle(List, Random)