Различные способы записать одиночный элемент в Java

Такая ковариантность на дженериках не поддерживается, но можно на самом деле сделать это с массивами:

object[] a = new string[] {"spam", "eggs"};

C# выполняет проверки на этапе выполнения, чтобы препятствовать тому, чтобы Вы поместили, скажем, int в a.

12
задан Jonik 5 January 2010 в 11:01
поделиться

6 ответов

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

18
ответ дан 2 December 2019 в 03:06
поделиться

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

Кстати, Джошуа Блох рекомендует (в Эффективная Java , 2-е изд., П. 3) реализовать синглтоны с использованием одноэлементного перечисления:

public enum SingletonObject { 
    INSTANCE;
}

Он дает следующее обоснование:

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

10
ответ дан 2 December 2019 в 03:06
поделиться

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

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

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

В Effective Java есть более подробная информация об этом, но у меня нет ее, чтобы найти номер элемента , Я

5
ответ дан 2 December 2019 в 03:06
поделиться

Я думаю, ваша проблема в том, что вы смешиваете синглтон и ленивую инициализацию. Синглтон может быть реализован с помощью различных стратегий инициализации :

  • инициализации при загрузке класса
  • ленивой инициализации, использующей блокировку с двойной проверкой
  • ленивой инициализации с однократной проверкой (с возможной повторной инициализацией)
  • ленивая инициализация, использующая загрузчик классов (идиома класса-держателя)

Все эти подходы обсуждаются в Эффективная Java 2-й пункт 71: разумно используйте отложенную инициализацию .

2
ответ дан 2 December 2019 в 03:06
поделиться

Я согласен с Anon, и в случае, когда я всегда хочу создать экземпляр синглтона, я бы использовал

public class SingletonObject
{
public static SingletonObject REF = new SingletonObject();

private SingletonObject()
{
    // no code req'd
}

}

-2
ответ дан 2 December 2019 в 03:06
поделиться

Во второй форме ваш синглтон с нетерпением загружен, и это на самом деле предпочтительная форма (и первая не является поточно-ориентированной, как вы сами упомянули) . Активная загрузка - неплохая вещь для производственного кода, но есть контексты, в которых вы можете захотеть отложить загрузку ваших синглтонов, как обсуждал автор Guice, Боб Ли, в Ленивая загрузка синглтонов , который я цитирую ниже:

Во-первых, зачем вам отложенная загрузка синглтон? В производстве вы обычно хотят с нетерпением загрузить все ваши синглтоны, чтобы вы ловили ошибки рано и возьмите любую производительность спереди, но на тестах и ​​во время разработка, вы хотите только загрузить что вам абсолютно необходимо, чтобы не терять время.

До Java 1.5 я лениво загружал синглтоны, использующие простой старый синхронизация, простая, но эффективная:

 статический экземпляр Singleton;

общедоступный статический синхронизированный синглтон getInstance () {
 если (экземпляр == нуль)
 экземпляр == новый синглтон ();
 возвратный экземпляр;
}

Изменения в модели памяти в 1.5 включил печально известный Double-Checked Идиома блокировки (DCL). Чтобы реализовать DCL, вы проверяете поле volatile в общий путь и синхронизировать только тогда, когда необходимо:

 статический изменчивый экземпляр Singleton;

public static Singleton getInstance () {
 if (instance == null) {
 синхронизированный (Singleton.class) {
 если (экземпляр == нуль)
 экземпляр == новый синглтон ();
 }
 }
 возвратный экземпляр;
}

Но volatile не намного быстрее чем синхронизировано , синхронизировано равно довольно быстро в настоящее время, а DCL требует больше кода, поэтому даже после выхода 1.5 Я продолжал использовать старый добрый синхронизация.

Каково же мое удивление сегодня, когда Джереми Мэнсон указал мне на Инициализация по требованию держателя (IODH) идиома , которая требует очень маленький код и ноль накладные расходы на синхронизацию. Ноль, как в даже быстрее, чем volatile . ИОДГ требуется такое же количество строк код как обычная старая синхронизация, и это быстрее, чем DCL!

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

 статический класс SingletonHolder {
 статический экземпляр синглтона = новый синглтон (); 
}

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

[...]

Обновление: Кредит, причитающийся, Действующая Java (авторское право 2001) подробно описал этот образец в пункте 48. Далее указывается, что вам все еще нужно использовать синхронизацию или DCL в нестатических контекстах.

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

Обратите внимание, что Джошуа Блох теперь рекомендует (начиная с Effective Java, 2-е изд.) реализовывать синглтоны с использованием одноэлементного перечисления , как указано Джоником .

18
ответ дан 2 December 2019 в 03:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: