Каждый из вас знает об этой особенности JMM, что иногда ссылка на объект может получить значение до завершения конструктора этого объекта.
В JLS7, стр. 17.5 заключительная семантика поля мы также можем прочитать:
Модель использования
final
полей проста: установитеfinal
поля для объекта в конструкторе этого объекта; и не записывайте ссылку на создаваемый объект в месте, где другой поток может видеть его до того, как конструктор объекта будет завершен. Если это будет выполнено, то, когда объект будет виден другим потоком, этот поток всегда будет видеть правильно сконструированную версиюfinal
полей этого объекта.(1)
И сразу после этого в JLS следует пример, демонстрирующий, как не гарантируется инициализация неокончательного поля (1Пример 17.5-1.1) (2)
:
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; // guaranteed to see 3
int j = f.y; // could see 0
}
}
}
Кроме того, в этом вопросе-ответе г-н Грей написал:
Если вы пометите поле как
final
, то конструктор гарантированно завершит инициализацию как часть конструктора. В противном случае вам придется синхронизировать замок перед его использованием.(3)
Итак, вопрос:
1) Согласно утверждению (1) мы должны избегать совместного использования ссылки на неизменяемый объект до того, как его конструктор будет завершен.
2) Согласно данному примеру JLS (2) и заключению (3) кажется, что мы можем безопасно поделиться ссылкой на неизменяемый объект до его конструктора, т.е. когда все его поля final
.
Нет ли противоречия?
EDIT-1: именно то, что я имел в виду. Если мы изменим класс в примере таким образом, это поле y
будет также final
(2):
class FinalFieldExample {
final int x;
final int y;
...
следовательно, в методе reader()
будет гарантировано, что:
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // guaranteed to see 4, isn't it???
Если да, то почему нам следует избегать записи ссылки на объект f
до завершения его конструктора (согласно (1)), когда все поля f
являются окончательными?