При чтении этой статьи DZone о параллелизме Java я задавался вопросом если следующий код:
private volatile List list;
private final Lock lock = new ReentrantLock();
public void update(List newList) {
ImmutableList l = new ImmutableList().addAll(newList);
lock.lock();
list = l;
lock.unlock();
}
public List get() {
return list;
}
эквивалентно:
private volatile List list;
public void update(List newList) {
ImmutableList l = new ImmutableList().addAll(newList);
list = l;
}
public List get() {
return list;
}
Попытка {} наконец {} блок была опущена для краткости. Я предполагаю, что класс ImmutableList действительно неизменная структура данных, которая содержит ее собственные данные, такие как тот, обеспеченный в библиотеке наборов Google. Так как переменная списка энергозависима и в основном что продолжается, copy-on-the-fly, не это безопасный просто пропустить при использовании блокировок?
В этом очень конкретном примере, я думаю, вы были бы в порядке, если бы не блокировали переназначение переменной.
В целом, я думаю, вам лучше использовать AtomicReference вместо изменчивой переменной, поскольку эффекты согласованности памяти такие же, а цель намного яснее.
Я думаю, что поведение синхронизации по умолчанию volatile не гарантирует поведение ReentrantLock, поэтому оно может помочь с производительностью. В остальном, думаю, нормально.
Если мы говорим о времени и видимости памяти. Волатильное считывание очень близко к тому времени, которое требуется для нормального считывания. Так что если вы делаете get() alot, то разница небольшая. Время, необходимое для записи волатильности, составляет около 1/3 времени для получения и освобождения блокировки. Так что ваше второе предложение немного быстрее.
Видимость памяти, как предлагают большинство людей, эквивалентна, т.е. любое чтение до получения блокировки перед любой записью после получения блокировки, аналогично любому чтению до получения волатильности перед любой последующей записью
.Да, оба этих примера кода ведут себя одинаково в параллельной среде. Неустойчивые поля никогда не кэшируются локально для потока , поэтому после того, как один поток вызывает update (), который заменяет список новым списком, get () для всех других потоков вернет новый список.
Но если у вас есть код, который использует его следующим образом:
list = get()
list = list.add(something) // returns a new immutable list with the new content
update(list)
, то он не будет работать должным образом ни в одном из этих примеров кода (если два потока делают это параллельно, то изменения, сделанные одним из них, могут быть перезаписан другим). Но если только один поток обновляет список или новое значение не зависит от старого значения, то проблем нет.
Дополнительные предметы для добавления в список без особого порядка:
Но в первом случае нет противоречий.
extern int i;
extern double i;
тоже не сработает. Так что если вы создадите класс А, то не сможете решить, кто такой А.
-121--3772226-Для обеспечения требуемой безопасности потока необходимо выполнить следующие критерии:
Поскольку здесь встречаются оба - код - безопасность потоков