单例

作者: 懒眉 | 来源:发表于2019-02-15 17:49 被阅读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;
        }
    }
    
    参考

    相关文章

      网友评论

          本文标题:单例

          本文链接:https://www.haomeiwen.com/subject/tzumeqtx.html