Потокобезопасные синглтоны в Java - PullRequest
38 голосов
/ 13 августа 2011

В статье в Википедии о Singletons упоминается несколько поточно-безопасных способов реализации структуры в Java.Что касается моих вопросов, давайте рассмотрим синглтоны, которые имеют длительные процедуры инициализации и к которым одновременно обращаются многие потоки.

Во-первых, является ли этот не упомянутый метод поточно-ориентированным, и если да, то для чего он синхронизируется?

public class Singleton {
    private Singleton instance;

    private Singleton() {
        //lots of initialization code
    }

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

Во-вторых, почему следующий поток реализации безопасен И ленив при инициализации?Что именно происходит, если два потока вводят метод getInstance() одновременно?

public class Singleton {
    private Singleton() {
        //lots of initialization code
    }

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

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

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

1 Ответ

46 голосов
/ 13 августа 2011

Ответ 1: static synchronized методы используют объект класса в качестве блокировки - т.е. в этом случае Singleton.class.

Ответ 2: Язык Java, среди прочего:

  • загружает классы при первом обращении к ним / их использовании
  • гарантирует, что перед разрешением доступа к классу все статические инициализаторы завершили

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

Все это означает, что у нас безопасная отложенная загрузка, и без любой требуется для синхронизации / блокировок!

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

кстати Статья Билла Пью стоит прочитать для полноты при понимании одноэлементных паттернов.

...