Почему Collections # shuffle не использует ThreadLocalRandom? - PullRequest
0 голосов
/ 11 июня 2018
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()?

Мои догадки:

  • Этот метод не обновлялся после выпуска ThreadLocalRandom в JDK 1.7
  • new Random() используется для обеспечения безопасности потока?

1 Ответ

0 голосов
/ 11 июня 2018

Методы Collections.shuffle(List) и Collections.shuffle(List, Random) были добавлены в JDK 1.2, тогда как класс ThreadLocalRandom не был добавлен до Java 7. Таким образом, для всех выпусков до Java 7 shuffle(List) использовал экземплярRandom.

Хотя источник случайности для shuffle(List) не указан, возможно, это было бы неожиданное изменение в поведении, если бы оно было изменено для использования другого источника случайности.Таким образом, метод был оставлен без изменений с использованием экземпляра Random.

Нет большой необходимости изменять его.Другие источники случайности, такие как ThreadLocalRandom и SecureRandom, являются подклассами Random, и их можно использовать для перестановки с использованием перегрузки двух аргументов shuffle(List, Random), если это то, что нужно приложению.

...