
Ваш код, запрашивающий значение переменной, и инициализатор - это вообще две разных сущности.
Ну это я для тех говорю, кто тоже поленился прочитать. Я вот весь джеп прочитал, но поленился понять.
Так вот, вызывающий клиентский код, который просит чтение переменной - очевидно должен быть блокирующим, если переменная ни разу не инициализировалась. Как только есть значение, он продолжается. Тормоза будут только один раз. Это неинтересная часть.
Интересно то, что вот инициализаторы-то могут, и скорей всего будут, выполняться не под локом, а под CAS-ом. "Lazy implies synchronized" не работает для инициализаторов.
Значит, существует ситуация, когда может запуститься сто пятьсот инициализаторов, а выиграет только один. Тот, которого выберет JVM. Способ выбора может быть любой, на откуп разработчиков конкретной реализации JVM (это то, что в C++ принято называть unspecified behavior - не описано в стандарте, да и разработчики не обязаны в своей документации уточнять).
Значит, в ленивый инициализатор нельзя положить никакие действительно важные данные. Например, нельзя положить туда коннект с БД, если у тебя по лицензии ограничение на количество коннекшенов - десять штук.
И тут можно сказать - а давайте сделаем как в Скале. Просто ебанем внутри инициализатора синхронизующий блок. "Lazy implies synchronized" своими руками, так сказать. А ВОТ ХУЙ. Потому что там же по спеке предлагается заставить JVM запретить любые сайд-эффекты до полной инициализации переменной. Точней, сайд-эффекты не должны быть видны никому, кроме создавшего их треда, и очевидно, синхронизованный блок к таковым не относится.
То есть, это какая-то очень не для всех фича.
Или может быть, нужно добросить больше модификаторов? Сделать synchronized lazy поле. А что - слово synchronized уже есть, в контексте поля раньше не имело смысла, почему бы не вставить туда?
В общем, какая-то ебанина с этим джепом. Очень интересно. Ебанина - это всегда очень интересно. Интересней может быть только Серьезная Ебанина, но о ней мы поговорим в следующих постах.