Шаблон "одиночка" и поврежденная проверенная дважды привязка реального JAVA-приложения

Я читал статью Перепроверяемая блокировка и Шаблон "одиночка", о том, как проверенная дважды блокировка повреждается, и некоторые связанные вопросы здесь на Переполнении стека.

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

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

Действительно ли это - настоящая проблема, и, если так, при каких условиях?

6
задан 3 revs, 2 users 87% 27 January 2014 в 15:04
поделиться

2 ответа

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

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

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

2
ответ дан 17 December 2019 в 00:07
поделиться

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

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

Я считаю, что реализация hashCode () String частично полагается на этот факт ... Потоки вычисляют hashCode, пока они не видят кеш, но в конечном итоге они начинают видеть . Между тем, дублирование вычислений означает лишь некоторую потерю времени CPU , а выгода от предотвращения эффекта памяти из-за изменчивой семантики превосходит эти потраченные впустую усилия (по крайней мере, поэтому, я думаю, они реализовали это таким образом). Допустимое использование идиомы (фактическая реализация 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
ответ дан 17 December 2019 в 00:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: