Насколько я понимаю, причина использования wrapper
состоит в том, что чтение неизменяемого объекта (все поля являются окончательными) является атомарной операцией.
Если wrapper
равно нулю, то это еще не является неизменнымобъект, и мы должны попасть в блок synchronized
.
Если wrapper
не равен нулю, то мы гарантируем полностью построенный объект value
, поэтому мыможет вернуть его.
В вашем коде проверка null
может быть выполнена без фактического чтения ссылочного объекта и, следовательно, без инициирования атомарности операции.Т.е. операция могла бы инициализировать helperWrapper
при подготовке к передаче результата new Helper()
в конструктор, но конструктор еще не был вызван.
Теперь я предполагаю, что последующий код в вашем примере будетчтение return helperWrapper.value;
, которое должно инициировать атомарное чтение ссылки, гарантируя, что конструктор завершает работу, но вполне возможно (семантика некоторых языков программирования '), что компилятору разрешено оптимизироватьчто не выполнить атомарное чтение, и, таким образом, он вернет не полностью инициализированный value
объект при точно правильных обстоятельствах.
Выполнение барьера с использованием локальной переменной и эталонной копии заставляет чтение и запись бытьatomic, и гарантирует, что код является поточно-ориентированным.
Я считаю, что основное понимание заключается в том, что неизменяемые ссылки чтения и записи являются атомарными, поэтому присваивание другой переменной является атомарным, но нулевое тестирование может не выполняться.