Это зависит от того, что вы называете «согласованным состоянием».Если вы видите нулевой указатель в том месте, где должен быть опубликованный объект, т. Е. Объект действительно выглядит так, как если бы он не был опубликован, считается «согласованным», то вы правы в том, что в примере получается «согласованность».
однако обратите внимание, что final
поля должны , а не изменять их значение.Если поток читает из final
, он может смело предположить, что значение поля не изменится позже.Реализация потока или (JIT) -компилятор может «кэшировать» значение поля в некоторой переменной (или регистре), потому что final
говорит ему, что значение, прочитанное один раз, остается неизменным.
В частности, код подобен
new Thread(new Runnable() {
public void run() {
while ( field == null ) {
// Wait a little...
}
// Field was initialized, go ahead.
}
}).start();
Вероятно, будет только два возможных результата: либо цикл никогда не будет введен, либо он станет бесконечным циклом.
Именно поэтому он особенно небезопасен получить доступ к final
полю до его инициализации;и final
поля гарантированно будут инициализированы только после завершения конструктора.
Проблема может стать более очевидной, если вы напишите полное имя поля в коде потока, который равен SomeClass.this.field
.Вы можете опустить его, но компилятор неявно сгенерирует для вас правильный доступ.Используя полное имя поля, вы можете более четко видеть, что поток обращается к SomeClass.this.field
до полной инициализации this
.Таким образом, фактически вы не публикуете согласованный объект SomeType
, но все еще несовместимый объект SomeClass
, который содержит это поле.