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;
I noticed that Collections#shuffle
uses new Random()
instead of ThreadLocalRandom.current()
, and I'm curious as to why. I wrote a benchmark comparing the two, and the method that uses ThreadLocalRandom.current()
is faster for each iteration. Here's the benchmark:
@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;
}
}
And the results:
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
So, why is new Random()
used over ThreadLocalRandom.current()
?
My guesses:
ThreadLocalRandom
in JDK 1.7new Random()
is used for thread-safety?The Collections.shuffle(List)
and Collections.shuffle(List, Random)
methods were added in JDK 1.2, whereas the ThreadLocalRandom
class wasn't added until Java 7. Thus, for all the releases prior to Java 7, shuffle(List)
used an instance of Random
.
Although the source of randomness for shuffle(List)
isn't specified, it would have possibly have been an unexpected change in behavior for it to be changed to use a different source of randomness. Thus, the method has been left as it stands, using an instance of Random
.
There's no great need to change it. Other sources of randomness, such as ThreadLocalRandom
and SecureRandom
, are subclasses of Random
, and they can be used for shuffling using the two-arg overload shuffle(List, Random)
if that's what the application needs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With