2013-05-15 4 views
0

Когда нужен синглтон, является ли статическое поле элегантным решением?Почему статический синглтон - это простое и изящное решение, чтобы избежать «DCL»?

class HelperSingleton { 
    static Helper singleton = new Helper(); 

    public static Helper getInstance() { 
     return singleton; 
    } 
    } 

Когда два потока доступ к getInstance в то же время, есть шанс, что поле singleton не инициализируется полностью? Или увидеть значения по умолчанию для полей вспомогательного объекта, а не значения, установленные в конструкторе? Статический синглтон также является ленивой инициализацией?

Я имею в виду, static Helper singleton = new Helper(); это этот атомный атом? И не вернет значения по умолчанию?

+1

Должно ли getInstance() быть статическим? –

+0

И должен быть частный конструктор. И «singleton» должен быть закрытым и окончательным. И в идеале класс должен быть «окончательным». –

+0

getInstance должен быть статичным, и ваш конструктор должен быть закрытым, если вы хотите применить синглтон. [edit] dangit @JonSkeet, вы украли мой ответ, и вы были быстрее меня :-p –

ответ

1

1) Когда поток обращается к статическому getInstance, загрузчик первого раза должен загружать класс HelperSingleton, и он блокирует другой поток до загрузки класса. Таким образом, существует неявная синхронизация. J.Bloch «Эффективная Java» Пункт 71 Современная виртуальная машина будет синхронизировать доступ к полю только для инициализации класса. После инициализации класса VM будет исправлять код, чтобы последующий доступ к полю не включал никаких проверок или синхронизации.

2) Ваш сингл ленив, потому что есть только одна точка доступа - getInstance. По требованию создается не только экземпляр, но и весь класс загружается по требованию. Класс не будет инициализирован до его использования [JLS, 12.4.1].

+0

Есть ли официальный документ о пункте 1, как вы упомянули? – znlyj

+0

[JLS 12.4.2] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2) – NINCOMPOOP

+0

Я думаю, что эффективная Java J.Bloch может быть поскольку автор руководил разработкой и внедрением многих функций платформы Java. –

1

Я думаю, что самое элегантное решение для одноточечного это:

public enum Singleton { 

    INSTANCE; 

    public Singleton getInstance() { 
     return INSTANCE; 
    } 
} 

Использование одноплодной картина несколько проблематично, потому что иногда вы не знаете, что вы на самом деле есть только один из них. Рассмотрим пример, например, когда вы используете загрузчики классов.

This вопрос (и прочее) есть подробное объяснение кстати.

0

Если бы это было так:

class HelperSingleton { 
    static Helper singleton = null; 
    public static Helper getInstance() { 
     if(singleton == null) { 
     singleton = new Helper(); 
     } 
     return singleton; 
    } 
} 

Там может быть возможность здесь:

  1. Тема 1 вызывает метод getInstance() и определяет, что singleton является null.

  2. Нить 1 входит в блок if, но перед тем, как создать новый экземпляр, вытесняется Thread 2.

  3. Резьба 2 вызывает метод getInstance() и определяет, что экземпляр null.

  4. Thread 2 входит в блок if и создает новый объект Helper и присваивает этому новому объекту переменную singleton.

  5. Резьба 2 возвращает ссылку на объект Singleton.

  6. резьба 2 вытесняется Темой 1.

  7. резьбы 1 начинается, где она была прервана и выполняет singleton = new Helper();, что приводит к другому объекту Singleton создается.

  8. Тема 1 возвращает этот объект.

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

static Helper singleton = new Helper(); 

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

+0

Спасибо, но я хочу знать, это статический помощник singleton = new Helper(); всегда возвращать полностью инициализированную ссылку на клиента? – znlyj