Синглтон дизайн шаблон двойной проверки блокировки - PullRequest
0 голосов
/ 30 сентября 2019
if (searchBox == null) { //1
    synchronized (SearchBox.class) {
        if (searchBox == null) {  //2
            searchBox = new SearchBox();
        }
    }
}

вот мой пользовательский класс для шаблона синглтона. в этом коде я использую двойную проверку блокировки, как описано выше. Поскольку я читаю много постов в каком-то источнике, они говорят, что двойная проверка полезна, потому что она предотвращает одновременное выполнение двух параллельных потоков и создание двух разных объектов. Согласно концепции потоков, за один раз планировщик потоков выполняет только один поток. Тогда как 2 потока попытаются выполнить приведенный выше код.

Пожалуйста, объясните мне. Что я понял не так?

Спасибо :))

Ответы [ 4 ]

0 голосов
/ 30 сентября 2019

Дважды проверенная блокировка имеет серьезные недостатки. Проблема в том, что этот оператор почти наверняка присваивает несколько переменных:

searchBox = new SearchBox();

Помимо присвоения searchBox, будет также несколько других назначений для инициализации нового экземпляра SearchBox.

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

Это означает, что если поток A создает синглтон, а затем поток B приходит и впоследствии находит searchBox != null, то поток B не войдет в synchronized блок и поток B могут видеть одноэлементный объект в неинициализированном или частично инициализированном состоянии.

Одноэлементный объект должен быть безопасно опубликован . Комментарий Энди Тернера к исходному вопросу (см. Выше) называет несколько различных способов сделать это.


PS: Вы можете «исправить» двойную проверку блокировки, объявив переменную searchBox равной volatile, но тогда стоимость доступа к searchBox становится почти такой же высокой, как стоимость блокировки замка. Лучше просто использовать один из шаблонов безопасной публикации, упомянутых выше.

0 голосов
/ 30 сентября 2019

загрузчик классов сначала загрузит статические поля, поэтому экземпляр будет доступен до того, как какой-либо поток вызовет метод getInstance (), поэтому для эффективного и чистого Singleton рассмотрите возможность использования этого метода и избегайте дорогостоящей синхронизации

public class SearchBox{
private static SearchBox instance = new SearchBox();
private SearchBox(){throw new OperationNotAllowedException();}
public static SearchBox getInstance(){ 
return instance;
}
public SomeReturn instanceMethod(){return ...} 
0 голосов
/ 30 сентября 2019

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

if (searchBox == null) { //1
  synchronized (SearchBox.class) {
    if (searchBox == null) {  //2
        searchBox = new SearchBox();
        }
   }
}

Тогда зачем нам внешнее условие if? Для улучшения производительности.

Допустим, у нас нет первого, если блок и объект searchbox уже созданы. Потоки будут заблокированы из-за синхронизированной блокировки. В таких сценариях внешний if блок остановит поток, вступающий в стадию ожидания.

Альтернативный подход, вы можете использовать статический внутренний класс для реализации шаблона Singleton

public class Singleton  {    
    private static class SingletonHolder {    
        public static final Singleton instance = new Singleton();
    }    

    public static Singleton getInstance() {    
        return SingletonHolder.instance;    
    }    
}

Источник для приведенного выше фрагмента: почему статический внутренний класс синглтонового потока безопасен

0 голосов
/ 30 сентября 2019

Вы не хотите, чтобы 2 потока выполняли код одновременно . Это синглтон . Single тонн. В любой момент времени должен быть только один экземпляр объекта. Если два потока запускают один и тот же код одновременно, они могут случайно создать два searchBox es, и тогда это не будет single ton, не так ли?

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

...