"Двойная проверка блокировки повреждена" только для Java?
страница http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html говорит, что блокировка с двойным проверкой ошибочна в java. Мне просто интересно, относится ли это также к другим языкам (С#, Vb, С++ и т.д.).
Я читал Двойной проверенный шаблон блокировки: Разбито или нет?, Является ли это ломаной двойной проверенной блокировкой?, Как разрешить "Двойное блокирование блокировки" , Декларация на Java?, чтобы быть правдивой, я не знаю, что такое общий консенсус. некоторые говорят, что его сломанные другие говорят "нет".
В любом случае, мой вопрос в том, относится ли это также к другим языкам (С#, Vb, С++ и т.д.)
Ответы
Ответ 1
Двойная проверенная блокировка в Java безопасна, ПРЕДОСТАВЛЯЕТСЯ, ЧТО:
- переменная экземпляра объявляется как
volatile
, AND
- JVM правильно реализует спецификацию JSR-133; то есть он совместим с Java 5 и более поздними версиями.
Мой источник - это FAQ о JSR-133 (Java Memory Model) - Джереми Мэнсон и Брайан Гетц, февраль 2004 г.. Это подтверждается Goetz в ряде других мест.
Однако, как говорит Гетц, это идиома, время которой прошло. Незаконная синхронизация в Java теперь очень быстрая, поэтому он рекомендует просто объявить метод getInstance()
как synchronized
, если вам нужно выполнить ленивую инициализацию. (И я полагаю, что это относится и к другим языкам...)
Кроме того, при прочих равных условиях, это плохая идея написать код, который работает на Java 5, но ненадежен в более старых JVM.
Хорошо, а как насчет других языков? Ну, это зависит от того, как реализована идиома, и часто на платформе.
-
С# - согласно fooobar.com/questions/74096/..., зависит от платформы, должна ли переменная экземпляра быть изменчивой. Однако Wikipedia говорит, что если вы используете volatile
или явные барьеры памяти, идиома может быть реализована безопасно.
-
VB - согласно Wikipedia идиома может быть реализована безопасно с использованием явных барьеров памяти.
-
С++ - в соответствии с Wikipedia идиома может быть реализована безопасно с помощью volatile
в Visual С++ 2005. Но другие источники говорят, что в целом спецификация языка С++ не обеспечивает достаточных гарантий для volatile
. Однако блокировка с двойной проверкой может быть реализована в контексте версии языка С++ 2011 - fooobar.com/questions/126649/....
(Примечание: я просто подытоживаю некоторые источники, которые я нашел, которые кажутся мне последними... и звуковыми. Я не эксперт на С++, С# или VB. Пожалуйста, прочитайте связанные страницы и сделайте свои собственные суждения. )
Ответ 2
В этой статье Википедии рассматриваются java, С++ и .net(С#/vb) http://en.wikipedia.org/wiki/Double-checked_locking
Ответ 3
Это сложный вопрос, в котором есть поле противоправной информации.
Часть проблемы состоит в том, что существует несколько вариантов блокировки с двойной проверкой:
- Поле, проверенное на быстром пути, может быть изменчивым или нет.
- Существует однополюсный вариант и двухполюсный вариант двойной проверки блокировки.
И не только это, разные авторы имеют другое определение того, что означает, что шаблон является "правильным".
- Определение # 1. Широко признанная спецификация языка программирования (например, ECMA для С#) гарантирует правильность шаблона.
- Определение # 2: шаблон работает на практике в конкретной архитектуре (обычно x86).
Как ни неприятно, как может показаться, много кода там зависит от определения № 2.
В качестве примера возьмем С#. В С# шаблон с двойной проверкой (как обычно реализуется) является правильным в соответствии с определением № 1 тогда и только тогда, когда поле является изменчивым. Но если мы рассмотрим определение № 2, почти все варианты верны для X86 (т.е. Работают), даже если поле является энергонезависимым. В Itanium вариант с одним полем работает, если поле является энергонезависимым, но не двухполюсным вариантом.
Несчастливое следствие состоит в том, что вы найдете статьи, в которых явно противоречивы утверждения о правильности этого шаблона.
Ответ 4
Как говорили другие, эта идиома имела свое время. FWIW, для ленивой инициализации .Net теперь предоставляет встроенный класс: System.Lazy<T>
(msdn). Не знаю, доступно ли что-то подобное в java.
Ответ 5
Он был ошибочным в Java, он был исправлен на Java 5. Тот факт, что был сломан, был скорее проблемой реализации в сочетании с недоразумением, чем технически "плохая идея".