【发布时间】:2018-11-20 03:38:56
【问题描述】:
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;
我注意到Collections#shuffle 使用new Random() 而不是ThreadLocalRandom.current(),我很好奇为什么。我写了一个比较两者的基准测试,使用ThreadLocalRandom.current() 的方法每次迭代都更快。这是基准:
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 15, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 20, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(5)
public class MyBenchmark {
@Param({"10", "1000", "100000"})
private int i;
private List<Integer> list;
private static final Random RANDOM = new Random();
@Setup
public void initialize() {
list = ThreadLocalRandom.current()
.ints(i)
.boxed()
.collect(Collectors.toList());
}
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
@Benchmark
public List<Integer> oldMethod() {
Collections.shuffle(list, RANDOM);
return list;
}
@Benchmark
public List<Integer> newMethod() {
Collections.shuffle(list, ThreadLocalRandom.current());
return list;
}
}
结果:
Benchmark (i) Mode Cnt Score Error Units
MyBenchmark.newMethod 10 avgt 100 60.802 ± 0.785 ns/op
MyBenchmark.newMethod 1000 avgt 100 6879.496 ± 15.638 ns/op
MyBenchmark.newMethod 100000 avgt 100 1248858.889 ± 33632.559 ns/op
MyBenchmark.oldMethod 10 avgt 100 90.636 ± 1.379 ns/op
MyBenchmark.oldMethod 1000 avgt 100 9740.442 ± 57.373 ns/op
MyBenchmark.oldMethod 100000 avgt 100 1511428.034 ± 27744.775 ns/op
那么,为什么new Random() 被使用而不是ThreadLocalRandom.current()?
我的猜测:
- 自 JDK 1.7 中
ThreadLocalRandom发布以来,此方法尚未更新 -
new Random()用于线程安全?
【问题讨论】:
-
我猜这是你的第一个猜测。 Java 充满了可以(甚至应该)重新编写的遗留代码,但不是出于兼容性原因。
-
最有可能? JDK 设计者不想在 Collections API 中构建基于
ThreadLocal的内存泄漏。 -
AFAICT Java 开发人员没有公开声明重写无错误代码以利用以后(也许更好)的 API 的政策。如果真的没有这样的公共政策,这真的是在征求人们对是否重写的意见,这对 SO 来说是题外话。
标签: java random collections shuffle