2016-04-07 2 views
0

В соответствии с этим post, класс одноэлементного потока должен выглядеть так, как показано ниже. Но мне интересно, нужно ли добавить ключевое слово volatile в переменную static CrunchifySingleton instance. Поскольку, если экземпляр создан и хранится в кэше CPU, в это время он не записывается обратно в основную память, между тем другой поток вызывает метод getInstance(). Возникает ли проблема непоследовательности?Нужно ли добавлять ключевое слово volatile, чтобы гарантировать потокобезопасный класс singleton в java?

public class CrunchifySingleton { 

    private static CrunchifySingleton instance = null; 

    protected CrunchifySingleton() { 
    } 

    // Lazy Initialization 
    public static CrunchifySingleton getInstance() { 
     if (instance == null) { 
      synchronized (CrunchifySingleton.class) { 
       if (instance == null) { 
        instance = new CrunchifySingleton(); 
       } 
      } 
     } 
     return instance; 
    } 
} 
+3

Lazy initialized Singletons - это отходы; Синглтоны в целом - плохая идея.Google написали программное обеспечение, чтобы идентифицировать их для удаления из своего кода. Почему вы их используете? – duffymo

ответ

0

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

1

Код, который вы цитируете, разбит на Java. Да, вам нужно volatile и, по крайней мере, Java 5, чтобы обеспечить безопасный поток идиомы с двойной проверкой. И вы также должны добавить локальную переменную в свою ленивую инициализацию для повышения производительности. Подробнее об этом читайте здесь: https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java

+2

Я бы не направил никого в DCL в 2016 году. Текущий стандарт - [enum singleton] (http://keaplogik.blogspot.fi/2013/12/the-java-enum-singleton-pattern.html). – Kayaman

+0

Я просто не спрашивал, является ли его версия потокобезопасной, и это был ответ. – Vampire

+0

И кстати. шаблон enum singleton хорош, но вы не можете делать ленивую инициализацию, если вам это нужно, не так ли? – Vampire

3

I комментарий echo @ duffymo выше: ленивые одиночные игры нигде не так полезны, как они изначально появляются.

Однако, если вы абсолютно необходимы использовать лениво-конкретизированный синглтон, то lazy holder idiom, является гораздо более простым способом для достижения безопасности потока:

public final class CrunchifySingleton { 
    private static class Holder { 
    private static final CrunchifySingleton INSTANCE = new CrunchifySingleton(); 
    } 

    private CrunchifySingleton() {} 

    static CrunchifySingleton getInstance() { return Holder.INSTANCE; } 
} 

Кроме того, обратите внимание, что по-настоящему синглтон, класс должен запретить как для создания экземпляра, так и для подкласса - конструктор должен быть private, а класс должен быть final, соответственно.

+0

частный конструктор и конечный класс на самом деле не нужны. частный конструктор да, или кто-то может просто создать экземпляр. Но если у вас есть частный конструктор, класс неявно окончательно в любом случае. Но, отметив это как окончательное, он ясно заявляет, конечно. :-) – Vampire

2

Да, если ваш экземпляр Singleton не volatile или даже если это volatile но вы используете достаточно старую JVM, нет никаких упорядочиваний гарантий для операций, в которых линия

instance = new CrunchifySingleton(); 

разлагается в отношении к volatile магазин.

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

Если вы хотите узнать больше о скрытых проблемах с Double-Checked Locking, в частности, на Java, см. The "Double-Checked Locking is Broken" Declaration.

Ленивый держатель идиома хороший образец, который обобщает хорошо для общего статического поля отложенной загрузки, но если вам нужен безопасный и простой шаблон Singleton, я рекомендовал бы, что рекомендует Джош Блох (от Эффективное Java славы) - Java Enum Singleton:

public enum Elvis { 
    INSTANCE; 

    public void leaveTheBuilding() { ... } 
} 
0

Вам нужно volatile в этом случае, но лучшим вариантом является использование либо enum, если он является лицом без гражданства

enum Singleton { 
    INSTANCE; 
} 

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

Смежные вопросы