Вот мой одноэлементный класс.
Статическое поле instance
не является изменчивым, поэтому возникает проблема изменения порядка / видимости. Для ее решения поле экземпляра val
делается окончательным. Поскольку экземпляр построен правильно, его клиенты всегда должны видеть инициализированное поле val
, если они вообще видят экземпляр.
static class Singleton {
private static Singleton instance;
private final String val;
public Singleton() { this.val = "foo"; }
public static Singleton getInstance() {
if (instance == null)
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
return instance;
}
public String toString() { return "Singleton: " + val; }
}
Однако есть еще одна проблема - у меня есть два незащищенных чтения поля "instance", которые можно (?) Переупорядочить, чтобы клиент мог получить null вместо реального значения:
public static Singleton getInstance() {
Singleton temp = instance;
if (instance != null) return temp;
else { /* init singleton and return instance*/ }
}
Чтобы обойти это, я чувствую, что могу ввести локальную переменную:
public static Singleton getInstance() {
Singleton temp = instance;
if (temp == null)
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
temp = instance;
}
}
return temp;
}
Кажется, это решает проблему, поскольку существует только одно незащищенное чтение значения, поэтому ничего действительно плохого не должно происходить. Но ... Я только что изменил поток программы без (почти?) Изменения его однопоточной семантики. Означает ли это, что компилятор может просто отменить мой обходной путь, поскольку это преобразование безопасно, и нет способа заставить этот код работать, не установив правильную связь «происходит раньше» с volatile?
java.util.concurrent
. - person Boris Pavlović   schedule 22.08.2014