Это из JLS 17.5:
Модель использования полей final проста. Задайте последние поля для объекта в конструкторе этого объекта. Не пишите ссылку на создаваемый объект в месте, где другой поток может видеть его до того, как конструктор объекта завершит работу. Если это соблюдается, то когда объект виден другим потоком, этот поток всегда будет видеть правильно построенную версию последних полей этого объекта. Он также будет видеть версии любого объекта или массива, на которые ссылаются эти последние поля, которые, по крайней мере, так же актуальны, как и последние поля.
Обсуждение в JLS 17.5 включает этот пример кода:
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
}
}
}
Я попытался повторно использовать этот код, чтобы воспроизвести описанную выше ситуацию, и вот что у меня есть:
public class FinalFieldThread extends Thread {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadB.start();
threadA.start();
//threadB.start();
}
}
class ThreadA extends Thread {
@Override
public void run() {
System.out.println("ThreadA");
FinalFieldExample.writer();
}
}
class ThreadB extends Thread {
@Override
public void run() {
System.out.println("ThreadB");
FinalFieldExample.reader();
}
}
Я могу проверить, как final читается правильно, но как я могу реплицировать, когда он не читается правильно (то есть когда есть ссылка на протектор до того, как конструктор закончил?)