单例

2019-02-15  本文已影响2人  懒眉

使用单例设计模式的类只有一个对象实例,基于此核心来编写代码。

public class LazySingleton {
    private volatile static LazySingleton ton = null;
    
    private LazySingleton(){}
    
    public  static  LazySingleton lzTon() {
        if(null == ton){
            synchronized(LazySingleton.class){
                if(null == ton)
                    ton = new LazySingleton();
            }
        }
        return ton;
    }
}
public class HungrySingleton {
    private static final HungrySingleton ton = new HungrySingleton();
    
    private HungrySingleton() {}
    
    public static HungrySingleton hslton(){
        return ton;
    }
}
public class SynthesisSingleton {
    private static class Singleton{
        public static final SynthesisSingleton ton = new SynthesisSingleton();
    }
    
    public SynthesisSingleton() {}
    
    public static final SynthesisSingleton ssl(){
        return Singleton.ton;
    }
}
//枚举能规避序列化和线程安全的问题
public enum EnumSingleton {
    TON;
    public void fun(){
        System.out.println("枚举单例");
    }
}

上述单例基本达到了类只有一个对象实例的核心目标,但也不是无懈可击,比如反射创建实例,反序列化得到的实例除了枚举单例都是新对象,下面以饿汉式和枚举单例参考。

public class MainTest {
    
    /**
     * 反射测试
     * @throws Exception
     */
    public static void reflectTest() throws Exception
    {
        {
            HungrySingleton ton = HungrySingleton.hslton();
            Class cla = HungrySingleton.class;
            Constructor co = cla.getDeclaredConstructor(null);
            co.setAccessible(true);
            HungrySingleton ton1 = (HungrySingleton) co.newInstance(null);
            System.out.println(ton);
            System.out.println(ton1);
        }
        
        {
            EnumSingleton ton = EnumSingleton.TON;
            Class cla = EnumSingleton.class;
            Constructor co = cla.getDeclaredConstructor(null);
            co.setAccessible(true);
            EnumSingleton ton1 = (EnumSingleton) co.newInstance(null);
            System.out.println(ton);
            System.out.println(ton1);
        }
        
    }
    
    /**
     * 序列化测试
     */
    public static void serializ() throws Exception{
        {
            HungrySingleton ton = HungrySingleton.hslton();
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/HungrySingleton.txt"));
            oos.writeObject(ton);
            oos.flush();
            oos.close();
            
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/HungrySingleton.txt")); 
            HungrySingleton ton1 = (HungrySingleton) ois.readObject();
            ois.close();
            System.out.println(ton);
            System.out.println(ton1);
        }   
        {
            EnumSingleton ton = EnumSingleton.TON;
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/EnumSingleton.txt"));
            oos.writeObject(ton);
            oos.flush();
            oos.close();
            
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/EnumSingleton.txt")); 
            EnumSingleton ton1 = (EnumSingleton) ois.readObject();
            ois.close();
            System.out.println(ton);
            System.out.println(ton1);
        }
    }
    
    public static void main(String[] args) throws Exception{
        serializ();
        reflectTest();
    }
    
}

最终结果是饿汉式序列化反序列化,反射前后对象不一致,而枚举单例则一致。很显然枚举单例经过了考验,那怎么避免饿汉式不能唯一实例呢,最后的单例守护文章里面提到了解决方案

public class HungrySingleton implements Serializable{
    private static final long serialVersionUID = 1L;
    private static final HungrySingleton ton = new HungrySingleton();
    
    private HungrySingleton() {
        //防止反射
        if(null != ton){
            throw new RuntimeException();
        }
    }
    public static HungrySingleton hslton(){
        return ton;
    }
    private Object readResolve(){
        //防反序列化
        return ton;
    }
}
参考
上一篇下一篇

猜你喜欢

热点阅读