2010-12-05 2 views
1

Следующий фрагмент прямо вперед,Singleton шаблон

public MyClass getInstance() { 
    if(uniqueInstance == null) { 
     uniqueInstance = new MyClass(); 
    } 
    return uniqueInstance; 
} 

Что делает следующий делать?

public MyClass getInstance() { 
    if(uniqueInstance == null) { 
     synchronized(MyClass.class) { 
      uniqueInstance = new MyClass(); 
     } 
    } 
    return uniqueInstance; 
} 

ответ

5

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

Чуть более безопасный подход добавляет дополнительный nullcheck, также известный как double-checked locking.

public MyClass getInstance() { 
    if (uniqueInstance == null) { 
     synchronized(MyClass.class) { 
      if (uniqueInstance == null) { 
       uniqueInstance = new MyClass(); 
      } 
     } 
    } 
    return uniqueInstance; 
} 

Однако, я обычно предпочитаю Just Create One pattern над Singleton.

+0

«Чуть более безопасно» ... Я не был бы слишком уверен в этом: http://www.google.ca/search?q=double+checked+locking+is+broken – 2010-12-05 06:05:48

3

Это немного страховка для безопасности потоков.

Из JavaWorld статьи here:

Синхронизация метод гарантирует , что вызов метода не может быть прервана .

Основная идея заключается в том, что если у вас нет синхронизированного блока можно на 2 потока для вызова GetInstance и переинициализации объекта, тем самым потенциально потери каких-либо данных о состоянии (если вы должны даже иметь данные о состоянии в a singleton)

1

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

3

IMHO Сначала вы должны начать с самых простых вариантов. Самый простой синглтон - это перечисление с одной записью. Учитывая, что классы загружаются лениво, это все равно даст вам ленивую загрузку, если напрямую не ссылаться на класс, и это происходит не случайно.

enum Singleton { 
    INSTANCE; 
} 

Чтобы избежать аварии, вы можете использовать внутренний класс.

class Singleton { 
    static class SingeltonHolder { 
     static final Singleton INSTANCE = new Singleton(); 
    } 
    public static Singleton getInstance() { 
     return SingletonHolder.INSTANCE; 
    } 
} 

Примечание; ни одно решение не нуждается в синхронизации, потому что они используют тот факт, что загрузка классов является потокобезопасной.

Вкратце; Бывают ситуации, когда требуется блокировка, но не делайте ее более сложной, чем она должна быть.

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