Может ли Семафор безопасно использовать идиому двойной проверки блокировки? - PullRequest
3 голосов
/ 02 ноября 2010

Является ли следующий Thead Safe в Java?

public class TestDCL{
    private static final Semaphore lock = new Semaphore(1);
    private Object instance;

    public Object m(){
        if(instance == null){
            lock.acquire();
            if(instance == null){
                instance = new Object();
            }
            lock.release();
        }
        return instance; 
    }
}

Ответы [ 3 ]

2 голосов
/ 02 ноября 2010

Это не потокобезопасно. Оператор new Object(); не является атомарной операцией. instance перестает быть null, когда для него выделяется память. Новый поток, который достигает первого условия if после выделения памяти для instance, но перед вызовом его конструктора вернет частично созданный объект. Если вы пытаетесь реализовать потокобезопасный синглтон, используйте решение Билла Пью , которое является и поточно-ориентированным, и ленивым.

1 голос
/ 03 ноября 2010

Согласен с предыдущими постами Тима. Волатильность делает для видимости, и причина двойной проверки блокировки была описана как умная, но сломанная вокруг частично построенных объектов (согласованность кэша / оптимизация JVM).

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

Я бы также подчеркнул старое предупреждение, чтобы не оптимизировать рано. Знаете ли вы, что грубая синхронизация замедляет работу приложения? Обычно медленная конкуренция блокировок, а не ключевое слово syncrhonization per-sa. Быстрый тест с syncrhonized и DCL подтвердит.

0 голосов
/ 03 ноября 2010

Ответ, это зависит. Ваш instance изменчив или неизменен? Если instance содержит изменяемое состояние, вы должны объявить его как volatile. Причина, по которой вы должны это сделать, не имеет ничего общего с частично построенными объектами, как предлагает @Vijay Mathew, но вместо этого связана с видимостью потоков. Изменения, внесенные в состояние вашего экземпляра-одиночки в одном потоке, не обязательно будут видны другому потоку. Использование ключевого слова volatile гарантирует, что оборудование будет использовать какой-то механизм для очистки кэша для удаления устаревших данных.

Параллелизм Java на практике, глава 16.2.3, описывает идиомы безопасной инициализации и содержит ленивую идиому инициализации. 16.2.4 обсуждается идиома блокировки с двойной проверкой.

...