Singleton using AtomicReference

邮差的信 提交于 2019-12-12 08:03:29

问题


Is it correct implementation of lazy-initializing singleton using AtomicReference? If no - what are the possible issues?

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();
    }

}

回答1:


No, this is bad:

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();
}

Using an AtomicReference is a nice idea, but it won't work because Java doesn't have lazy evaluation.


The classic post 1.5 singleton methods are:

Eager Singleton:

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

Lazy Singleton with inner holder class:

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;
}

You should probably stick with one of these




回答2:


You've got a race condition, in that you may return an instance of the Singleton before init is called on it. You could wrap singleton if you wanted a once-only init. However, we know how to implement singletons in a simple, efficiently manner and mutable singletons are pure evil..




回答3:


You can prevent serialization scenario to make it singleton forcefully .

all your constructor should be private.




回答4:


I don't see why you would need to use AtomicReference for a singleton: AtomicReference allows you to atomically change ther reference to the object -- and in the case of a singleton there should be one instance only and no one should be able to change that ever again for the execution of your app. Also your code is not synchronized, so concurrent requests will end up creating multiple instances of the Singleton class (as pointed out by @Sean Patrick Floyd for instance).




回答5:


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)
}



回答6:


The updated code adds deserialisation with readResolve.

Two obvious problems here.

  • Back references can read the original object before readResolve is called.

  • Even though the class has only a private constructor, it is not final. final is really important. A hand-crafted (or created with a jig Singleton implementation) octet sequence could deserialise into a subclass. (The no-args constructor of the most derived non-serialisable base class (which must be accessible to the most base serialisable class) is called by the deserialisation machinery.) An inaccessible readResolve is not called for subclasses.



来源:https://stackoverflow.com/questions/5938163/singleton-using-atomicreference

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!