Это мой код "безопасная" синглтон?


Мне было интересно, если мой код будет производить настоящий синглтон. Я создаю приложение для Android, и все виды деятельности должны получить доступ к моему API через один экземпляр SyncApi класс.

public class Api {

    private static SyncApi api = null;

    static {
        synchronized (api) {
            if (api == null) {
                api = new ApiFActory().getSyncApi();
            }
        }
    }

    public static SyncApi getInstance() {
        return api;
    }
}

Использование класса будет выглядеть так:

SyncApi api = Api.getInstance();
api.logOn("jjnguy", "pa55w0rd");


3182
38
задан 6 апреля 2011 в 03:04 Источник Поделиться
Комментарии
7 ответов

В Java есть устоявшаяся идиома для создания потокобезопасного синглтона, благодаря Биллу пью:

public class Api {
private Api() { }

private static class SingletonHolder {
public static final SyncApi INSTANCE = new ApiFactory().getSyncApi();
}

public static SyncApi getInstance() {
return SingletonHolder.INSTANCE;
}
}

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

41
ответ дан 6 апреля 2011 в 09:04 Источник Поделиться

Самый лучший и простой способ получает Джошуа блох в 《эффективная Java 2-е издание》

public enum Api {
INSTANCE;
}

вы можете использовать его, как это

Api api = Api.INSTANCE;

35
ответ дан 7 апреля 2011 в 03:04 Источник Поделиться

Если вы хотите потокобезопасным и ленивый, я полностью согласен с ответом , предусмотренных Конрад Рудольф.

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

Вот хорошая статья с множеством испытаний и примеры:
http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html

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

Вот статья об абсолютной синглтонов:
http://surguy.net/articles/communication-across-classloaders.xml

3
ответ дан 13 апреля 2011 в 03:04 Источник Поделиться

Ну, это определенно не Синглтон, потому что этот код является законным:
API-интерфейс.API-интерфейс=новый API();

Вы должны как минимум определить API для переменной в качестве окончательной и не менее закрытый конструктор, чтобы избежать создания экземпляра.

См. @Конрад Рудольф за предложенное решение.

3
ответ дан 8 июня 2012 в 09:06 Источник Поделиться

Настройки вашего API, чтобы нуль не помочь вам запятнать ваш исключение NullPointerException

synchronized (api) // api == null, you should use Api.class

Как одноэлементный, пожалуйста, пожалуйста, пожалуйста, используйте перечисление. Это рекомендуемый образец, начиная с Java 5. Теперь, если вы хотите ленивый нагрузки :

public class Api {

private Api() {}

private enum SingletonHolder {
INSTANCE;

private static final Api singleton = new Api();

Api getSingleton() {
return singleton;
}
}

public Api api() {
Api.SingletonHolder.INSTANCE.getSingleton();
}
}

Звоните :

 api().logOn("jjnguy", "pa55w0rd");

Вы вправе распоряжаться getSingleton() и доступ к синглтон непосредственно внутри API-интерфейс

public class Api {

private Api() {/*your costly init here*/}

private enum SingletonHolder {
INSTANCE;
private static final Api singleton = new Api();
}

public Api api() {
return Api.SingletonHolder.singleton;
}
}

3
ответ дан 21 июля 2013 в 12:07 Источник Поделиться

Я согласен с другими ответами, но ваша проблема, как вы указали, не имеют единый интерфейс, но есть один SyncApi экземпляр.

Вы не сможете запретить пользователю делать:

SyncApi api = new ApiFActory().getSyncApi();

Вы должны сделать SyncApi одноэлементный или инкапсулировать его использование в классе API и не предоставлять доступ к ней вне вашего API...

2
ответ дан 14 января 2013 в 11:01 Источник Поделиться

public class Singleton {
private static Singleton instance = null;

public static Singleton getInstance(){
if(null == instance){
synchronized(Singleton.class){
//double check
if(null == instance){
instance = new Singleton();
}
}
}
return instance;
}

}

Это может использоваться, чтобы гарантировать, создается только один экземпляр. Или просто использовать перечисления.

0
ответ дан 16 ноября 2013 в 03:11 Источник Поделиться