Или есть ли преимущество использования двойной проверки блокировки?
вопрос относится к поведению старых версий Java и старых реализаций алгоритма двойной проверки блокировки
Более новые реализациииспользованиеvolatile
и полагаться на немного изменилосьvolatile
семантика, поэтому онине сломана.
Утверждается, что присвоение полей всегда атомарно, за исключением полей long или double.
Но, когда я читаю объяснение того, почему блокировка двойной проверки нарушена, говорится, что проблема в операции присваивания:
// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
// other functions and members...
}
Поток A замечает, что значение не инициализировано, поэтому он получает блокировку и начинает инициализировать значение.Из-за семантики некоторых языков программирования код, сгенерированный компилятором, может обновлять совместно используемую переменную, чтобы указывать на частично сконструированный объект, прежде чем А завершит выполнение инициализации.Поток B замечает, что совместно используемая переменная была инициализирована (или она так выглядит), и возвращает ее значение. Поскольку поток B считает, что значение уже инициализировано, он не получает блокировку. Если B использует объект до того, как вся инициализация, выполненная A, будет видна B (либо потому, что A еще не завершила его инициализацию, либо потому, что некоторые из инициализированных значений в объекте еще не перколированы в используемую память B (когерентность кэша)) программа, скорее всего, потерпит крах.(изhttp://en.wikipedia.org/wiki/Double-checked_locking).
Когда это возможно? Возможно ли, что на 64-битной JVM операция присваивания не является атомарной? Если нет, то действительно ли нарушена «двойная проверка блокировки»?