Java final & Safe Publication
Когда я прочитал jsr-133-faq на вопрос "Как работают последние поля в новом JMM?", Он сказал:
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x;
int j = f.y;
}
}
}
Приведенный выше класс является примером того, как должны использоваться конечные поля. Читатель, выполняющий поток, гарантированно увидит значение 3 для fx, потому что оно является окончательным. Не гарантируется увидеть значение 4 для y, потому что оно не является окончательным.
Это сбивает меня с толку, потому что код в Writer не является безопасной публикацией, читатель, выполняющий поток, может увидеть, что f не равен null, но конструктор объекта, на который ссылается f, еще не завершен, поэтому, даже если x является финальным, поток, выполняющий читателя не может быть гарантировано увидеть значение 3 для FX
Это место, где я в замешательстве, пожалуйста, поправьте меня, если я ошибаюсь, большое спасибо.
1 ответ
В этом весь смысл, и это то, что хорошо в финальных полях в JMM. Да, компилятор, как правило, может назначить ссылку на объект еще до того, как объект будет полностью сконструирован, и это небезопасная публикация, поскольку доступ к объекту можно получить в частично сконструированном состоянии. Однако для конечных полей JMM (и компилятор) гарантирует, что все конечные поля будут подготовлены в первую очередь, прежде чем присваивать ссылку на объект. Публикация может все еще быть небезопасной, и объект все еще только частично создан, когда новый поток обращается к нему, но по крайней мере конечные поля будут в ожидаемом состоянии. Из главы 16.3 в Java параллелизма на практике:
Безопасность инициализации делает гарантии видимости только для значений, которые доступны через конечные поля на момент завершения конструктора. Для значений, достижимых через незавершенные поля, или значений, которые могут измениться после построения, необходимо использовать синхронизацию, чтобы обеспечить видимость.
Я также рекомендую прочитать главу 16.3 для более подробной информации.