Я думаю, что я прочитал, что последнее ключевое слово в поле гарантирует, что если поток 1 создает экземпляр объекта, содержащего это поле, тогда поток 2 всегда будет видеть инициализированное значение этого поля, если поток 2 имеет ссылку на объект ( при условии, что она была правильно построена). В JLS также говорится, что
[Thread 2] также будет видеть версии любого объекта или массива, на которые ссылаются те конечные поля, которые, по крайней мере, являются последними как конечные поля находятся. (раздел 17.5 JLS)
Это означает, что если у меня есть класс A
class A {
private final B b = new B();
private int aNotFinal = 2;
...
и класс B
class B {
private final int bFinal = 1;
private int bNotFinal = 2;
...
то aNotFinal не может быть инициализирован потоком времени 2, который получает ссылку на класс A, но поле bNotFinal является, поскольку B является объектом, на который ссылается конечное поле, как указано в JLS.
Есть ли у меня это право?
Edit:
Сценарий, в котором это может произойти, будет состоять в том, что если у нас есть два потока, одновременно выполняющих getA() в одном экземпляре класса C
class C {
private A a;
public A getA(){
if (a == null){
// Thread 1 comes in here because a is null. Thread B doesn't come in
// here because by the time it gets here, object c
// has a reference to a.
a = new A();
}
return a; // Thread 2 returns an instance of a that is not fully
// initialized because (if I understand this right) JLS
// does not guarantee that non-final fields are fully
// initialized before references get assigned
}
}