Синглтон ленивый против жаждущей реализации - PullRequest
24 голосов
/ 17 октября 2011

Если синглтон реализован следующим образом,

class Singleton {
    private static Singleton instance = new Singleton();

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

Чем эта реализация отличается от метода отложенной инициализации?В этом случае экземпляр будет создан, когда класс загружен, а сам класс загружен только при первом активном использовании (например, Singleton.getInstance (), а не при объявлении, например, Singleton singleton = null;)

Даже при ленивом подходе инициализации экземпляр создается по вызову getInstance ()

Я что-то здесь упускаю?

Ответы [ 6 ]

18 голосов
/ 17 октября 2011

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

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

Пожалуйста, обратитесь к этому учебнику от IBM для случая Singleton + Lazy Loading + Multithreaded Environment

=============== Редактировать 09/09/2018 ====================

Вы также должны посмотреть на создание объекта по шаблону здесь .

13 голосов
/ 17 октября 2011

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

class Logger {     
   private static Logger instance = new Logger(); 
   public static String LOG_LINE_SEPERATOR =  
      System.getProperty("line.separator");
   public static Logger getInstance() {  
          return instance;     
   } 

   public static String logPattern() {
       return null;
   }
} 

...

Logger.LOG_LINE_SEPERATOR; // load Logger instance or
Logger.logPattern(); // load Logger instance
7 голосов
/ 17 октября 2011

По указанным вами причинам это просто более сложный способ сделать то же самое, что и

enum Singleton {
    INSTANCE;
}

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

Примечание. Простая ссылка на класс не инициализирует класс.

например. Скажем, у вас плохо написанный класс, который нельзя инициализировать, пока не будет установлено какое-либо условие. В этом случае n должно быть ненулевым.

public class Main {
    public static void main(String ... args) {
        Class c= LazyLoaded.class;
        System.out.println(c);
    }

    static class LazyLoaded {
        static int n = 0;
        static {
            System.out.println("Inverse "+1000/n);
        }
    }
}

печать

class Main$LazyLoaded
1 голос
/ 19 октября 2017

Прежде всего, шаблон синглтона используется слишком часто. Что вы действительно хотите сделать, если хотите «одно из чего-то», так это объявить его одиночным в выбранной вами DI-структуре. Это эффективно управляемый синглтон, основанный на конфигурации, и высвобождает возможности для введения макетов для проведения надлежащего тестирования.

Почему бы не ленивый груз? Если ваш класс не имеет обширной подпрограммы инициализации в конструкции (которую я бы поспорил, также является анти-паттерном), то нет никакой выгоды и много недостатков для отложенной загрузки. Вы просто добавляете сложность и, возможно, нарушаете свою программу, если она не сделана правильно. Правильный способ (если необходимо) - использовать идиому держателя инициализации по требованию.

0 голосов
/ 09 июля 2019

Стремительная загрузка в одноэлементном шаблоне проектирования - это не процесс, в котором нам нужно инициализировать одноэлементный объект во время запуска приложения, а не по требованию, и держать его готовым в памяти для использования в будущем.Преимущества использования Eager Loading в шаблоне разработки Singleton состоят в том, что CLR (Common Language Runtime) позаботится об инициализации объекта и безопасности потока.Это означает, что нам не потребуется явно писать какой-либо код для обработки безопасности потоков в многопоточной среде.

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

Пожалуйста, обратитесь к следующим учебным пособиям по точечной сети, где вы можете найти наглядные примеры обоих.

https://dotnettutorials.net/lesson/lazy-vs-eager-loading-chsrap/

0 голосов
/ 04 января 2018

Для экземпляров с отложенной загрузкой, я использую как показано ниже.

class Singleton {
private static Singleton instance;
private Singleton(){

}
public static Singleton getInstance() {
    if(null==instance){
        synchronized(Singleton.class){
            if(null==instance){
                instance = new Singleton();
            }
        }
    }
    return instance;
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...