Я читаю книгу Брайана Гетца "Параллельность Java на практике".Пункты 3.5 и 3.5.1 содержат утверждения, которые я не могу понять.
Рассмотрим следующий код:
public class Holder {
private int value;
public Holder(int value) {
this.value = value;
}
public void assertValue() {
if (value != value) throw new AssertionError("Magic");
}
}
class HolderContainer {
// Unsafe publication
public Holder holder;
public void init() {
holder = new Holder(42);
}
}
Автор утверждает, что:
- В Java,Конструктор объекта сначала записывает значения по умолчанию во все поля перед запуском конструктора подкласса.
- Следовательно, значение по умолчанию для поля можно рассматривать как устаревшее значение.
- Поток может видеть устаревшее значение при первом чтении поля, а затем более актуальное значение в следующий раз.Вот почему assertN может выдать AssertionError.
Итак, согласно тексту, при некоторой неудачной синхронизации возможно, что значение = 0;и в следующий момент значение = 42.
Я согласен с пунктом 1, что конструктор объекта сначала заполняет поля значениями по умолчанию.Но я не понимаю пунктов 2 и 3.
Давайте обновим код авторов и рассмотрим следующий пример:
public class Holder {
int value;
public Holder(int value) {
//Sleep to prevent constructor to finish too early
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.value = value;
}
public void assertValue() {
if(value != value) System.out.println("Magic");
}
}
Я добавил Thread.sleep (3000), чтобы заставить потокждать, пока объект не будет полностью построен.
public class Tests {
private HolderContainer hc = new HolderContainer();
class Initialization implements Runnable {
public void run() {
hc.init();
}
}
class Checking implements Runnable {
public void run() {
hc.holder.assertValue();
}
}
public void run() {
new Thread(new Initialization()).start();
new Thread(new Checking()).start();
}
}
Например:
- первый поток входит в объект-держатель
- второй поток вызывает assertValue
Основной поток запускает два потока:
- новый поток (новая инициализация ()). Start ();Требуется 3 секунды, чтобы полностью построить объект Holder
- new Thread (new Checking ()). Start ();поскольку объект Holder, который еще не создан, код выдаст NullPointerException
Поэтому невозможно эмулировать ситуацию, когда поле имеет значение по умолчанию.
Мои вопросы:
- Автор был неправ по поводу этой проблемы параллелизма?
- Или невозможно эмулировать поведение для значений полей по умолчанию?