Исходный исходный код выглядит как
public static void shuffle(List<?> list) {
Random rnd = r;
if (rnd == null)
r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}
и указывает на точку позади дизайна.Код использует общее поле r
и не является потокобезопасным, но разработан таким образом, что последствия «безвредны».
Очевидно, что вы не должны разрабатывать свое программное обеспечение таким образом.Это зависит от экспертов для определенного программного обеспечения, где они думают, производительность имеет значение.(На самом деле этот метод shuffle
может не относиться к этой категории)
Так что для вашей альтернативы
private static Random r;
public static void shuffle(List<?> var0) {
if (r == null) {
r = new Random();
}
shuffle(var0, r);
}
последствия безопасности отсутствующего потока не будут безвредными.Тест r == null
и последующий вызов shuffle(var0, r)
несут различные чтения r
, и хотя должны быть только переходы от начального null
к инициализированному экземпляру Random
, чтение и запись могут восприниматься не по порядку, когдаМеханизм безопасного потока не используется, поэтому, когда происходит параллельная запись, r == null
может вычислять до false
, тогда как последующие shuffle(var0, r)
читают null
.
Это не делает этот вариант неправильным.Если вы задокументируете свой метод или содержащий его класс как не ориентированный на многопотоковое исполнение и требующий внешней синхронизации при использовании другими потоками, в этом нет ничего плохого.
Метод shuffle
класса Collections
читаетзначение r
в локальной переменной, чтобы гарантировать, что одно и то же значение будет использоваться тестом rnd == null
и вызовом shuffle(list, rnd)
.Так как это может считывать ссылку на экземпляр Random
, созданный другим потоком, он опирается на тот факт, что экземпляр Random
сам по себе является потокобезопасным, так как в противном случае при быстром чтении может возникнуть несовместимое состояние объекта.
Все еще возможно, что чтение пропустит значение, ранее записанное другим потоком, или что запись другим потоком произойдет между чтением null
и последующей записью ссылки на вновь созданный экземпляр Random
.Таким образом, вполне возможно, что несколько потоков будут создавать и использовать различные экземпляры Random
здесь, что рассматривается как «безвредные» последствия.
Как уже говорилось, вам не следует копировать этот шаблон.Скорее, решите либо для безопасности потоков, либо без безопасности потоков, и запишите свой код как таковой.