2014-02-20 3 views
-2

меня попросили в интервью, чтобы проверить, какие из следующих 2 способов объявить одноплодный класс лучше с надлежащей reasons.Can никому, пожалуйста, поделитесь некоторыми идеямиКакой лучший синглтон и почему?

public static Singleton getSingleInstance() { 
    if (singleInstance == null) { 
     synchronized (Singleton.class) { 
      if (singleInstance == null) { 
       singleInstance = new Singleton(); 
      } 
     } 
    } 
    return singleInstance; 
} 

OR 

public static synchronized Singleton getSingleInstance() { 
    if (singleInstance == null) { 
     singleInstance = new Singleton(); 
    } 
    return singleInstance; 
} 
+0

http://en.wikipedia.org/wiki/Singleton_pattern Википедия объясняет гораздо лучше, чем где-либо еще – spiderman

+1

Мое голосование за # 2 - причина, по которой проверка «null» выполняется в контексте синхронизированного блока ... Лучше решение будет заключаться в использовании 'enum' ... – MadProgrammer

+0

Первый будет работать лучше. http://en.wikipedia.org/wiki/Double-checked_locking – anonymous

ответ

0

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

0

Ответ зависит от того, что более важно, производительности или четкости кода. Для производительности первая лучше [2], но для удобочитаемости вторая лучше, поскольку меньшее количество строк кода легче понять и доказать, что они свободны от ошибок.

[2] Производительность будет зависеть от скорости волатильных чтений по сравнению с приобретением монитора в классе, определяющем метод singleton, при условии, что метод вызывается более одного раза. У меня нет количественного доказательства, но я бы предположил, что первое лучше.

Для чего это стоит, как Apache Commons LazyInitializer использует первый (http://commons.apache.org/proper/commons-lang/apidocs/src-html/org/apache/commons/lang3/concurrent/LazyInitializer.html):

@Override 
public T get() throws ConcurrentException { 
    // use a temporary variable to reduce the number of reads of the 
    // volatile field 
    T result = object; 

    if (result == null) { 
     synchronized (this) { 
      result = object; 
      if (result == null) { 
       object = result = initialize(); 
      } 
     } 
    } 

    return result; 
} 
0

полностью зависит от ваших потребностей.

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

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

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

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