0

Когда я просмотрел статью о DOUBLE-CHECKED LOCKING на http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html, я столкнулся с комментарием, в котором говорится: «Следует отметить, что DCL может, по сути, работать с некоторыми версиями некоторых JVM, поскольку только несколько JVM фактически реализуют JMM правильно. " Итак, я выводю из него, что JMM указывает, что синхронизированный блок является атомарным, даже если блоки не синхронизированы в других потоках. Я прав? (Я пытался прочитать JMM на веб-сайте oracle, но это было слишком абстрактно, и я сдался.)Определяет ли последний JMM синхронизированный блок как атомарный для других потоков, даже асинхронный?

+2

Синхронизированные блоки, безусловно, не являются атомарными, и я не вижу, как вы могли бы сделать вывод из этого комментария. –

+2

Нет, вы ошибаетесь. Прочтите спецификацию JMM, если у вас есть вопрос об этом. Любой может придумать какие-то необоснованные предположения, но вы не можете ожидать, что люди углублятся, чтобы опровергнуть это, если вы не потрудились прочитать то, о чем говорите –

ответ

2

Прежде всего, обратите внимание, что Брайан Гетц написал эту статью в 2001 году. Информация, изображаемая в этом документе статья не является более точной после implementation of JSR-133, пересмотренной модели памяти. Что, однако, правда, в том, что пример DCL статьи сломана:

class SomeClass { 

    private Resource resource = null; 

    public Resource getResource() { 
    if (resource == null) { 
     synchronized (this) { 
     if (resource == null) 
      resource = new Resource(); 
     } 
    } 
    return resource; 
    } 
} 

Используя приведенный выше код, то resource поле может наблюдаться быть не null в то время как конструктор экземпляра была еще не в полном объеме. Проблема заключается в том, что конструктор не гарантированно подвергается экспансии перед назначением поля, поскольку JVM может применять оптимизацию кода. Вызов конструктора должен поэтому скорее следует рассматривать как (в псевдокоде):

resource = alloc Resource; 
resource.new(); 

С этой информацией, можно увидеть, как начальная проверка resource == null может дать false другой поток еще до new называется то, что подвергает неполную экземпляр в другой поток. Этот другой поток никогда не войдет в синхронизированный блок и не дожидается завершения вызова конструктора.

В современной Java, однако, достаточно, чтобы поле resource было volatile. В этом случае DCL работает и даже достаточно эффективен, поскольку чтение изменчивого поля - not too expensive on most hardware. Алексей Шипилев обсудил результаты работы безопасного, ленивого издания in detail. DCL с volatile является распространенным образцом сегодня, например, используется Scala для его полей lazy.

Но для ответа на ваш реальный вопрос: в основном все реализации JVM реализуют модель памяти в более свободном режиме, чем ее спецификация. Таким образом, энергонезависимый DCL может работать только на многих машинах, несмотря на неправильную синхронизацию из-за детализации реализации. Однако вы никогда не должны кодировать реализацию, но всегда против спецификации. В противном случае ваш код может терпеть неудачу только иногда и только на некоторых машинах, что является ужасной ошибкой для отслеживания! Это не связано с тем, что блок synchronized является атомарным, он связан только с тем, как ваша виртуальная машина выполняет ваш код, где конструктор может случайно всегда выполняться до публикации вашего экземпляра в поле resource.

 Смежные вопросы

  • Нет связанных вопросов^_^