Синглтон-паттерн и сломанная двойная проверка блокировки в реальном Java-приложении - PullRequest
6 голосов
/ 20 марта 2010

Я читал статью Двойная проверка блокировки и шаблон Singleton , о том, как дважды проверенная блокировка сломана, и некоторые связанные вопросы здесь о переполнении стека.

Я использовал этот шаблон / идиому несколько раз без каких-либо проблем. Так как я использовал Java 5, моей первой мыслью было, что это исправлено в модели памяти Java 5. Однако в статье говорится:

Эта статья относится к памяти Java Модель до пересмотра для Java 5,0; утверждения об упорядочении памяти могут больше не соответствовать действительности. Однако, еще раз проверил идиому блокировки сломан под новую модель памяти .

Это реальная проблема, и если да, то при каких условиях?

Ответы [ 3 ]

3 голосов
/ 19 августа 2010

Иллюстрирующий пример синглтона с двойной проверкой блокировки, который выглядит умным, но сломанным

Запуск блока синхронизации гарантирует, что вы видите самые последние данные, но это не гарантирует переупорядочение, вы не можете ожидать последовательного просмотра данных, если только вы также в синхронизированном блоке. Это не гарантирует, что изменения переменных, выполненные в синхронизированном разделе, будут видны другим потокам. Только потоки, которые входят в синхронизированный блок, гарантированно видят изменения. Это причина, почему блокировка с двойной проверкой нарушена - она ​​не синхронизируется на стороне читателя. Поток чтения может видеть, что синглтон не равен нулю, но данные синглтона могут быть не полностью инициализированы (видимы) .

С другой стороны, упорядочение обеспечивается с помощью volatile, которое гарантирует упорядочение, например, запись в volatile singleton static field гарантирует, что запись в объект singleton будет завершена до записи в volatile статическое поле. Это не мешает созданию синглтона двух объектов; это обеспечивается синхронизацией . Класс финальных статических полей не должен быть изменчивым. В Java JVM решает эту проблему.

Больше информации можно найти в:

2 голосов
/ 20 марта 2010

У нас было приложение, которое использовало сломанную идиому двойной проверки, и оно функционировало очень долго - нет, на самом деле у меня никогда не возникало проблем с этой идиомой.Конечно, я исправил это независимо от этого.

Я предполагаю, что одна из причин этого заключается в том, что видимость потоков в конечном итоге будет достигнута в реальном мире.И как только оно достигнуто, оно остается.Так что да, будет очень трудно определить, возникла ли проблема.

Я полагаю, что реализация hashCode() String частично опирается на этот факт ... Потоки вычисляют hashCode, пока они не видяткеш, но со временем они начинают видеть.Между тем, повторяющиеся вычисления означают лишь некоторое потраченное впустую ЦП времени, а преимущество, связанное с отсутствием эффекта энергозависимой семантики в памяти, превосходит эти напрасные усилия (по крайней мере, поэтому они реализовали его таким образом, как я полагаю).Идиома, которая имеет правильное использование: (фактическая реализация String.hashCode ()):

/** Cache the hash code for the string */
private int hash; // Defaults to 0

public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

        for (int i = 0; i < len; i++) {
            h = 31*h + val[off++];
        }
        hash = h;
    }
    return h;
 }

Очевидно, что прежде чем использовать его, нужно много подумать и измерить.

2 голосов
/ 20 марта 2010

Для кого-то было бы трудно быть уверенным, что его приложение действительно было повреждено ошибкой блокировки с двойной проверкой. Действительно, многие приложения, которые использовали эту идиому, могут никогда не столкнуться с проблемой по разным причинам.

Однако это не значит, что вы должны его использовать. Сам факт того, что вероятность отказа не поддается количественной оценке, должен быть достаточным, чтобы убедить вас не использовать двойную проверку блокировки, тем более что существуют безопасные альтернативы.

Тебе просто повезло.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...