Синглтон с использованием AtomicReference - PullRequest
6 голосов
/ 09 мая 2011

Является ли правильной реализация синглтона с отложенной инициализацией с использованием AtomicReference?Если нет - каковы возможные проблемы?

import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicReference;

public class Singleton implements Serializable {

    private static final Singleton _instance = new Singleton();

    private static AtomicReference<Singleton> instance = new AtomicReference<Singleton>();

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance.compareAndSet(null, _instance)) {
            synchronized (_instance) {
                _instance.init();
                instance.set(_instance);
            }
        }
        return instance.get();
    }

    private void init() {
        // do initialization
    }

    private Object readResolve() throws ObjectStreamException {
        return getInstance();
    }

}

Ответы [ 6 ]

10 голосов
/ 09 мая 2011

Нет, это плохо:

public static Singleton getInstance() {
    // new "singleton" for every method call
    Singleton s = new Singleton();
                   ^^^^^^^^^^^^^^
    if (instance.compareAndSet(null, s)) {
        synchronized (s) {
            s.init();
        }
    }
    return instance.get();
}

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


Классические синглтон-методы post 1.5:

Eager Singleton:

public final class Singleton{
    private Singleton(){}
    private static final Singleton INSTANCE = new Singleton();
    public Singleton getInstance(){return INSTANCE;}
}

Ленивый синглтон с классом внутреннего держателя:

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

Enum Singleton:

public enum Singleton{
    INSTANCE;
}

Вы, вероятно, должны придерживаться одного из этих

1 голос
/ 09 мая 2011

У вас есть состояние гонки, в котором вы можете вернуть экземпляр Singleton до вызова init.Вы можете обернуть синглтон, если хотите один раз init.Тем не менее, мы знаем, как просто и эффективно реализовать синглтоны, а изменчивые синглтоны - чистое зло ..

0 голосов
/ 09 мая 2011

Обновленный код добавляет десериализацию с readResolve.

Две очевидные проблемы здесь.

  • Обратные ссылки могут прочитать исходный объект перед вызовом readResolve.

  • Несмотря на то, что класс имеет только закрытый конструктор, он не является final.final действительно важно.Созданная вручную (или созданная с помощью реализации jig Singleton) последовательность октетов может десериализоваться в подкласс.(Конструктор без аргументов самого производного несериализуемого базового класса (который должен быть доступен для самого базового сериализуемого класса) вызывается механизмом десериализации.) Недоступный readResolve не вызывается для подклассов.

0 голосов
/ 09 мая 2011
public static Singleton getInstance() {
    Singleton s=instance.get();
    if(s!=null)synchronized(s){return s;}//already initialised ->return it
    Singleton s = new Singleton();
    synchronized(s){
         if(instance.compareAndSet(null, s))//try to set
              s.init();
    }
    return instance.get();//use the one that is there after CaS (guaranteed not null)
}
0 голосов
/ 09 мая 2011

Я не понимаю, почему вам нужно было бы использовать AtomicReference для синглтона: AtomicReference позволяет вам атомарно изменить ссылку на объект - а в случае с синглтоном должен быть только один экземпляр и никто не сможет изменить это снова для выполнения вашего приложения. Кроме того, ваш код не синхронизирован, поэтому одновременные запросы в конечном итоге создадут несколько экземпляров класса Singleton (как указано, например, @Sean Patrick Floyd).

0 голосов
/ 09 мая 2011

Вы можете предотвратить сценарий сериализации , чтобы сделать его одноразовым.

весь ваш конструктор должен быть приватным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...