Шаблон дизайна Java Singleton: вопросы

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

Он, кажется, наполовину удовлетворен ответом, но я хочу знать

  • Сколько раз мы можем реализовать шаблон дизайна Singleton в Java?
  • Какова область действия Singleton Object и как она работает в JVM? Я знаю, что у нас всегда будет один экземпляр Singleton Object, но какова реальная область действия этого объекта, это в JVM или если работает несколько приложений, чем область видимости на основе контекста внутри JVM, я был очень обеспокоен этим и не смог дать удовлетворительного объяснения?
  • Наконец, он спросил, возможно ли использовать Singleton Object with Clusters с объяснением, и есть ли способ, чтобы Spring не реализовал шаблон Singleton Design, когда мы вызываем вызов Bean Factory, чтобы получить объекты?

Любые входы будут высоко оценены в отношении Singleton и какие основные вещи следует иметь в виду при работе с Singletons?

Спасибо.

Ответ 1

Существует несколько способов реализации шаблона Singleton в Java:

// private constructor, public static instance
// usage: Blah.INSTANCE.someMethod();
public class Blah {
    public static final Blah INSTANCE = new Blah();
    private Blah() {
    }
    // public methods
}

// private constructor, public instance method
// usage: Woo.getInstance().someMethod();
public class Woo {
    private static final Woo INSTANCE = new Woo();
    private Woo() {
    }
    public static Woo getInstance() {
        return INSTANCE;
    }
    // public methods
}

// Java5+ single element enumeration (preferred approach)
// usage: Zing.INSTANCE.someMethod();
public enum Zing {
    INSTANCE;
    // public methods
}

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

Относительно использования singleton в кластере... Я не уверен, что определение "использование"... является ли интервьюер подразумевающим, что один экземпляр создается в кластере? Я не уверен, что это имеет большой смысл...?

Наконец, определение не одиночного объекта в spring выполняется просто через атрибут singleton = "false".

Ответ 2

Я не согласен с @irreputable.

Объем Singleton - это node в дереве Classloader. Его содержащий загрузчик классов и любые дочерние загрузчики классов могут видеть Singleton.

Важно понимать эту концепцию области, особенно на серверах приложений, которые имеют сложные иерархии Classloader.

Например, если у вас есть библиотека в файле jar в системном пути к классам сервера приложений, и эта библиотека использует Singleton, то Singleton будет (вероятно) одинаковой для каждого приложения, развернутого в сервер приложений. Это может быть или не быть хорошо (зависит от библиотеки).

Classloaders - это IMHO, одна из самых важных концепций в Java и JVM, и Singletons играют в этом, поэтому я думаю, что для программиста Java важно "заботиться".

Ответ 3

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

public enum Singleton { ONE_AND_ONLY_ONE ; ... members and other junk ... }

Что касается синглтонов на более высоких уровнях - возможно, я глупый, но моя склонность состояла в том, чтобы распространять JVM самостоятельно (и ограничивать загрузчики классов). Тогда перечисление будет адекватным заданию.

Ответ 4

Singleton обычно реализуется путем статического объекта экземпляра (private SingletonType SingletonType.instance), который создается лениво посредством статического метода SingletonType SingletonType.getInstance(). Есть много подводных камней для использования синглтонов, поэтому многие, по сути, считают, что синглтон является анти-шаблоном дизайна. Учитывая вопросы о Spring, интервьюер, вероятно, искал понимания не только синглтонов, но и их ловушек, а также обходной путь для этих ловушек, известных как инъекция зависимости. Вы можете найти видео на странице Google Guice, особенно полезной для понимания ловушек одиночек и того, как DI обращается к этому.

Ответ 5

3: Наконец, он спросил, можно ли использовать Singleton Object with Clusters с объяснением, и есть ли способ, чтобы Spring не реализовал Singleton Design Pattern, когда мы вызываем вызов Bean Factory, чтобы получить объектов?

Первая часть этого вопроса трудно ответить без технологического контекста. Если на кластерной платформе есть возможность совершать вызовы на удаленных объектах, как если бы они были локальными объектами (например, как это возможно при использовании EJB с использованием RMI или IIOP под капотом), то да, это можно сделать. Например, объекты однопользовательского объекта JVM могут быть прокси-серверами для одноэлементного объекта кластера, который изначально был расположен/подключен через JNDI или что-то еще. Но кластерные синглтоны являются потенциальным узким местом, потому что каждый вызов одного из прокси-серверов singleton приводит к (дорогому) RPC к одному удаленному объекту.

Вторая часть вопроса состоит в том, что Spring Bean Заводы могут быть сконфигурированы с различными областями. Значение по умолчанию - для одиночных (с областью действия на уровне webapp), но они также могут быть охвачены сеансом или запросом, или приложение может определить свой собственный механизм обзора.

Ответ 6

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

Я не думаю, что программисту Java не стоит заботиться, если только он не пишет некоторые рамки. "Один на ВМ" - достаточно хороший ответ. Люди часто говорят об этом, строго говоря, они говорят "один на загрузчик классов".

Можем ли мы иметь один синглтон на кластер? Хорошо, что игра понятий. Я не стал бы признавать, что интервьюер так говорит.

Ответ 7

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

  • То, где он становится волосатым. Например, если класс инициализируется внутри контекста приложения Tomcat, то время жизни экземпляра singleton привязано к этому контексту. Но может быть трудно предсказать, где будут инициализироваться ваши классы; поэтому лучше не делать никаких предположений. Если вы хотите абсолютно убедиться, что для каждого контекста есть только один экземпляр, вы должны привязать его как атрибут ServletContext. (Или пусть это будет зависеть от него.)

  • -

  • Не уверен, что я понимаю вопрос, но если вы говорите о том, что один экземпляр singleton, который делится между несколькими узлами кластера, я думаю, что EJB делает это возможным (через удаленный beans), хотя я Я никогда не пробовал. Не знаю, как это работает Spring.

Ответ 8

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

Это может быть достигнуто с использованием статических методов или путем инъекции зависимостей или с использованием шаблона factory. Средства несущественны. В случае обычного подхода protected constructor(), пользователь должен использовать статический метод для доступа к singleton. В случае DI потребитель добровольно отказывается от контроля над созданием класса и вместо этого полагается на структуру DI, чтобы вставлять экземпляр в себя.

Как указывалось другими плакатами, загрузчик классов в java определял сферу действия singleton. Синглтоны в кластерах обычно "не единичные экземпляры", а набор экземпляров, которые демонстрируют подобное поведение. Они могут быть компонентами SOA.

Ответ 9

Следующий код из здесь

Ключевым моментом является то, что вы должны Override метод clone... Википедия пример также полезен.

public class SingletonObject
{
  private SingletonObject()
  {
    // no code req'd
  }

  public static SingletonObject getSingletonObject()
  {
    if (ref == null)
        // it ok, we can call this constructor
        ref = new SingletonObject();        
    return ref;
  }

  public Object clone()
    throws CloneNotSupportedException
  {
    throw new CloneNotSupportedException(); 
    // that'll teach 'em
  }

  private static SingletonObject ref;
}

Ответ 10

Запрос 1:

Различные способы создания Singleton

  • Normal Singleton: статическая инициализация
  • ENUM
  • Lazy Singleton: двойная блокировка Singleton и: Initialization-on-demand_holder_idiom singleton

Посмотрите ниже код:

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

    public static Singleton getInstance(){
        return instance; 
    }
    public enum EnumSingleton {
        INSTANCE;   
    }   
    public static void main(String args[]){
        System.out.println("Singleton:"+Singleton.getInstance());
        System.out.println("Enum.."+EnumSingleton.INSTANCE);
        System.out.println("Lazy.."+LazySingleton.getInstance());
    }
}
final class LazySingleton {
    private LazySingleton() {}
    public static LazySingleton getInstance() {
        return LazyHolder.INSTANCE;
    }
    private static class LazyHolder {
        private static final LazySingleton INSTANCE = new LazySingleton();
    }
}

Связанные вопросы SE:

Что такое эффективный способ реализации одноэлементного шаблона в Java?

Запрос 2:

Один экземпляр Singleton создается за ClassLoader. Если вы хотите избежать создания объекта Singleton во время Serializaiton, переопределите ниже метод и верните тот же экземпляр.

private Object readResolve()  { 
    return instance; 
}

Запрос 3:

Чтобы достичь уровня кластера Singleton среди нескольких серверов, сохраните этот объект Singleton в распределенных кэшах, например Terracotta, Coherence и т.д.

Ответ 11

Синглтон - это шаблон дизайна для создания.

Цель шаблона проектирования Singleton:

  • Убедитесь, что класс имеет только один экземпляр и предоставляет глобальную точку доступ к нему.
  • Инкапсулированная инициализация "точно в момент времени" или "инициализация на первое использование ".

Здесь показаны три типа реализации.

  • Инициализация во времени (выделяет память во время первого запуска, даже если вы ее не используете)

    class Foo{
    
        // Initialized in first run
        private static Foo INSTANCE = new Foo();
    
        /**
        * Private constructor prevents instantiation from outside
        */
        private Foo() {}
    
        public static Foo getInstance(){
            return INSTANCE;
        }
    
    }
    
  • Инициализация при первом использовании (или ленивая инициализация)

    class Bar{
    
        private static Bar instance;
    
        /**
        * Private constructor prevents instantiation from outside
        */
        private Bar() {}
    
        public static Bar getInstance(){
    
            if (instance == null){
                // initialized in first call of getInstance()
                instance = new Bar();
            }
    
            return instance;
        }
    }
    
  • Это еще один стиль инициализации Lazy, но преимущество в том, что это решение является потокобезопасным, не требуя специальных языковых конструкций (т.е. волатильных или синхронизированных). Подробнее на SourceMaking.com

    class Blaa{
    
        /**
         * Private constructor prevents instantiation from outside
         */
        private Blaa() {}
    
        /**
         * BlaaHolder is loaded on the first execution of Blaa.getInstance()
         * or the first access to SingletonHolder.INSTANCE, not before.
         */
        private static class BlaaHolder{
            public static Blaa INSTANCE = new Blaa();
        }
    
        public static Blaa getInstance(){
            return BlaaHolder.INSTANCE;
        }
    
    }