В чем преимущество решения Билла Пью над решением Lazy Initialized Singleton? - PullRequest
0 голосов
/ 18 сентября 2018

Билл Пью раствор

public class ThreadSafeSerializedSafeSingleton implements Serializable {

    private ThreadSafeSerializedSafeSingleton() {
    }

    private static class SingletonHelper {
        private static final ThreadSafeSerializedSafeSingleton instance = new ThreadSafeSerializedSafeSingleton();
    }

    public static ThreadSafeSerializedSafeSingleton getInstance() {
        return SingletonHelper.instance;
    }

}

VS

Lazy Initialized Thread Safe Singleton

public class ThreadSafeSingleton {

    private static ThreadSafeSingleton instance;

    private ThreadSafeSingleton() {
    }

    public static synchronized ThreadSafeSingleton getInstance() {
        if (instance == null) {
            instance = new ThreadSafeSingleton();
        }
        return instance;
    }

}

Ответы [ 3 ]

0 голосов
/ 18 сентября 2018

Это на самом деле называется паттерном "держатель".

Его преимущества изложены здесь :

Инициализация статического вспомогательного поля откладывается до вызова метода getInstance (). Необходимые отношения «происходит до» создаются комбинацией действий загрузчика классов, загружающих и инициализирующих экземпляр Holder, и гарантий, предоставляемых моделью памяти Java (JMM). Эта идиома - лучший выбор, чем дважды проверенная идиома блокировки для ленивой инициализации статических полей [Bloch 2008]. Однако эту идиому нельзя использовать для ленивой инициализации полей экземпляров [Bloch 2001].

«Реальный» ответ здесь: существует много решений проблемы «двойной проверки блокировки», и у всех них есть немного разные плюсы / минусы.

0 голосов
/ 18 сентября 2018

Преимущества решения Билла Пью над представленной реализацией ленивого инициализированного синглтона связаны с производительностью. Рассмотрим следующий сценарий.

Экземпляр уже инициализирован и , причем два потока одновременно запрашивают экземпляр .

  • Для отложенной инициализированной реализации, поскольку метод синхронизирован, один из потоков заблокируется.
  • Для реализации Билла Пью блокировки не будет.

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

Синглтон с двойной проверкой:

public final class DoubleCheckedLockingSingleton {

    private static volatile DoubleCheckedLockingSingleton instance;

    private DoubleCheckedLockingSingleton(){
        if(instance!=null)
            throw new RuntimeException();
    }

    public static final DoubleCheckedLockingSingleton getInstance(){
        if(instance==null){
            synchronized(DoubleCheckedLockingSingleton.class) {
                if(instance==null)
                    instance = new DoubleCheckedLockingSingleton();
            }
        }
        return instance;
    }

}

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

  • Блокировка с двойной проверкой: потоки будут блокироваться, только если они одновременно инициируют создание экземпляра. Вы должны перепроверить для instance == null внутри синхронизированного блока, поскольку два потока могут (потенциально, хотя и маловероятно - лучший вид ошибки) поменяться местами между первым if и синхронизированным блоком. Вы также должны объявить переменную volatile, чтобы использовать JMM, который «случается до» гарантии volatile (так что вы уверены, что проверка instance==null не вернет false, пока экземпляр не будет полностью инициализирован ).
  • Паттерн держателя: потоки будут блокироваться, только если они одновременно инициируют создание экземпляра. Все, что вам нужно знать, это то, что классы в Java загружаются лениво, с блокировкой от JVM (поэтому блокировка и видимость выполняются сразу после установки, без дополнительных усилий с вашей стороны).

Лично я предпочитаю шаблон держателя, а не блокировку с двойной проверкой, поскольку причины, по которым он работает, кажутся более понятными (по крайней мере, мне).

В качестве заключительного замечания, если ваши требования позволяют это (например, если вы используете инфраструктуру DI, такую ​​как Spring), лучшим способом реализации синглтона было бы позволить Spring предоставить синглтон для вас (с помощью * 1040). * с одноэлементной областью по умолчанию).

0 голосов
/ 18 сентября 2018

Очевидное преимущество состоит в том, что в методе Bill Pugh нет синхронизации.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...