单例模式的四种实现

6 阅读1分钟

饿汉式单例

  • 示例

    • JDK:Runtime.getRuntime()(饿汉式)
    • Spring:DefaultSingletonBeanRegistry(通过 ConcurrentHashMap 管理单例 Bean)
//饿汉式单例
public class HungerSingleton implements Serializable {
    private static final HungerSingleton INSTANCE=new HungerSingleton();
    private HungerSingleton(){
        //防止反射破坏单例
        if (INSTANCE!=null){
            throw new RuntimeException("禁止反射攻击");
        }
    }
    public static HungerSingleton getINSTANCE(){
        return INSTANCE;
    }
    //防止序列化破坏单例,单例类中定义private Object readResolve()方法, 方法返回单例对象。因为在反序列化时如果类中有个叫readResolve的方法,就会执行这个方法并返回结果。
    protected Object readResolve(){
        return INSTANCE;
    }
}

双重检查锁


public class DCLSingleton {
    private static volatile DCLSingleton instance;

    private DCLSingleton(){
        if (instance!=null){
            throw new IllegalStateException("禁止反射破坏单例模式");
        }
    }
    
    public static DCLSingleton getInstance(){
        if (instance==null){
            synchronized (DCLSingleton.class){
                if (instance==null){
                    instance=new DCLSingleton();
                }
            }
        }
        return instance;
    }
}

枚举

public enum EnumSingleton {
    INSTANCE;
}

静态内部类方式


public class StaticClassSingleton {
    private StaticClassSingleton(){
        if (internalClass.INSTANCE!=null){
            throw new IllegalStateException("禁止反射破坏单例");
        }
    }
    static class internalClass{
        static final StaticClassSingleton INSTANCE=new StaticClassSingleton();
    }
    public static StaticClassSingleton getInstance(){
        return internalClass.INSTANCE;
    }
}

尝试破坏单例模式


public class DestorySingletonTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //反射破坏单例模式
        reflection();
        //序列化破坏单例模式
//        serialization();
    }

    private static void serialization() {
        HungerSingleton instance = HungerSingleton.getInstance();
        try {
            //序列化
            ObjectOutput output=new ObjectOutputStream(new FileOutputStream("singleton.ser"));
            output.writeObject(instance);
            output.close();
            //反序列化
            ObjectInput input=new ObjectInputStream(new FileInputStream("singleton.ser"));
            HungerSingleton o = (HungerSingleton) input.readObject();
            input.close();
            System.out.println(instance.hashCode());
            System.out.println(o.hashCode());
            System.out.println(instance==o);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private static void reflection() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Constructor<HungerSingleton> constructor = HungerSingleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        HungerSingleton hungerSingleton = constructor.newInstance();
        System.out.println(HungerSingleton.getInstance()==hungerSingleton);
    }
}