#java #locking #volatile
#java #блокировка #volatile
Вопрос:
Мое понимание volatile заключается в том, что оно гарантирует, что значение всегда считывается из памяти, поэтому, насколько я вижу, в следующем примере myObject
переменная должна быть volatile, чтобы избежать NullPointerException
возникновения:
private final Object lock = new Object();
private MyObject myObject = null;
//...
synchronized (lock) {
if (myObject == null) {
myObject = new MyObject();
}
myObject.blah();
// some other stuff that I want synchronized
}
myObject
только когда-либо затрагивается в синхронизированном блоке. lock
используется только каждый для синхронизации этого блока.
Это правильно?
Итак, слегка перефразировав, мой вопрос … представьте, что два потока попадают в этот код. Первый поток блокирует и устанавливает MyObject, вызовы .blah()
и любой другой код в синхронизированном блоке и выходит из синхронизированного блока. Это позволяет второму потоку входить в синхронизированный блок. myObject
Есть ли вероятность, что он все еще может оценить значение volatile без установки значения volatile myObject == null
true
?
Комментарии:
1.Является
myObject
volatile? Кроме того, являетсяObject lock
постоянным для всех экземпляров вашего класса?2. @LuiggiMendoza — см. Редактирование.
3. Есть ли какой-либо другой код, который можно установить
myObject
наnull
?4. @SotiriosDelimanolis — нет, представьте, что этот код является автономным.
5. Я думаю, что может быть шанс, у меня был не очень удачный опыт использования
synchronized
блоков, когда возникали неожиданные результаты и синхронизация не работала, особенно в начале процесса. Лучше использоватьReentrantLock
. А что касаетсяvolatile
, в данном случае это не имеет ничего общего с синхронизацией, поэтому не требуется.
Ответ №1:
synchronized
Блок гарантирует, что обновления памяти будут видны другим потокам. Нет необходимости создавать myObject
volatile.
Из встроенных блокировок и синхронизации:
Когда поток освобождает внутреннюю блокировку, между этим действием и любым последующим получением той же блокировки устанавливается связь «происходит до».
Комментарии:
1. Я провел некоторое исследование, так как мне было интересно, почему я думал, что вам нужно ключевое слово volatile. Я полагаю, что это было связано с DCL, это: cs.umd.edu /~pugh/java/memoryModel/DoubleCheckedLocking.html . Теперь я прав, говоря, что, поскольку у меня нет проверки на null за пределами моего цикла синхронизации, мне не нужна проверка?
Ответ №2:
Я думаю, что volatile здесь не нужен, потому что каждый поток, который переходит в синхронизированный блок, проверяет ссылки на MyObject, поэтому MyObject должен быть создан, когда первый поток переходит в блок, другие потоки защищены проверкой, является ли MyObject not null . Для меня выглядит хорошо.
РЕДАКТИРОВАТЬ: я надеюсь, что есть только один блок, в котором вы хотите использовать ссылку myObect, и вы не изменяете эту ссылку до или после блока синхронизации.
Комментарии:
1. Но нет ли вероятности, что значение может находиться где-то в кэше и, следовательно, приводить к NPE?
2. Нет. Такой возможности нет.
3. В коде, который вы вставляете, каждый поток (но только один одновременно) будет проверять значение MyObject, затем запускать метод blah, поэтому все остальные потоки будут ждать. Но вы не можете реализовать второй блок, в котором вы устанавливаете MyObject=null , потому что тогда произойдет что-то вроде того, что вы сказали. Если вы хотите установить значение null для MyObject, вам нужно сделать это в одном блоке.