zoukankan      html  css  js  c++  java
  • Java 单例设计模式

    1、懒汉模式

    class LazySingleton{
    
        //volatile防止指令重排
        private static volatile LazySingleton SINGLETON ;
    
        //构造方法私有化
        private LazySingleton(){}
    
        /*
          双重检查锁DCL(Double Check Lock)
          检查两次是否为null,再加一把锁
         */
         public static LazySingleton getInstance(){
            if (SINGLETON == null){
                synchronized (LazySingleton.class){
                    if (SINGLETON == null){
                        SINGLETON = new LazySingleton();
                    }
                }
            }
    
            return SINGLETON;
        }
    
    }
    

    为什么加锁?

    保证线程安全,防止多线程情况下多个线程同时执行新建对象方法。

    为什么不使用synchronized直接锁getInstance()方法?

    同一时间只能有一个线程访问方法,效率低下。

    为什么加volatile关键字?

    防止执行new MySingleton()时发生指令重排。

    2、饿汉模式

    /**
     * 饿汉式--单例模式
     */
    class HungrySingleton{
        
        //类加载的是否就初始化了,不用担心线程安全
        private static HungrySingleton SINGLETON  = new HungrySingleton();
    
        //构造方法私有化
        private HungrySingleton(){}
    
        public static HungrySingleton getInstance(){
            return SINGLETON;
        }   
    }
    

    缺点:
    实例在类初始化一开始就被创建了,哪怕后来根本没有使用它。

    3、静态内部类

    /**
     * 静态内部类(懒汉式)--单例模式
     */
    class InnerClassSingleton{
    
        //静态内部类创建对象
        private static class InnerClass{
            private static InnerClassSingleton singleton = new InnerClassSingleton();
        }
    
        private InnerClassSingleton(){}
    
        public static InnerClassSingleton getInstance(){
            return InnerClass.singleton;
        }
    }
    

    通过JVM类加载来解决线程安全。
    缺点:可以通过反射创建对象

    4、反射攻击

    我们通过静态内部类创建单例对象。虽然我们的构造方法是private的,当时仍然可以通过狗仔方法创建对象。

    public class TestDemo3 {
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            //单例创建的对象
            System.out.println(InnerClassSingleton.getInstance());
            //通过反射创建对象
            Constructor<InnerClassSingleton> constructor = InnerClassSingleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            InnerClassSingleton innerClassSingleton = constructor.newInstance();
            System.out.println(innerClassSingleton);
        }
    }
    
    com.zjw.InnerClassSingleton@1540e19d
    com.zjw.InnerClassSingleton@677327b6
    

    发现两个对象不一致。。

    解决办法:在构造方法处检查对象是否创建

    /**
     * 静态内部类(懒汉式)--单例模式
     * 解决反射创建问题
     */
    class InnerClassSingleton{
    
        //静态内部类创建对象
        private static class InnerClass{
            private static InnerClassSingleton singleton = new InnerClassSingleton();
        }
    
        //在构造方法检查对象是否创建
        private InnerClassSingleton(){
            if (InnerClass.singleton!=null){
                throw new RuntimeException("单例已经创建,不能再新建了");
            }
        }
    
        public static InnerClassSingleton getInstance(){
            return InnerClass.singleton;
        }
    }
    

    5、枚举类型

    /**
     * 枚举类型--单例模式
     */
    public enum EnumSingleton {
    
        SINGLETON;
    
        public void print(){
            System.out.println(this.hashCode());
        }
    }
    
    
    public class TestDemo4 {
        public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
            EnumSingleton singleton1 = EnumSingleton.SINGLETON;
            EnumSingleton singleton2 = EnumSingleton.SINGLETON;
            System.out.println(singleton1);
            System.out.println(singleton2);
            singleton1.print();
            singleton2.print();
    
            Constructor<EnumSingleton> constructor = EnumSingleton.class.getDeclaredConstructor(String.class, int.class);
            constructor.setAccessible(true);
            EnumSingleton singleton = constructor.newInstance("SINGLETON", 0);
        }
    }
    

    结果:

    SINGLETON
    SINGLETON
    356573597
    356573597
    Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
    	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
    	at com.zjw.TestDemo4.main(TestDemo4.java:17)
    
    
    

    发现通过枚举类型创建的单例是不能通过反射创建的。

    6、序列化

    /**
     * 反序列化--单例模式
     */
    class HungrySingleton implements Serializable {
    
        private static final long serialVersionUID = 23423454L;
    
        private static HungrySingleton SINGLETON  = new HungrySingleton();
    
        //构造方法私有化
        private HungrySingleton(){}
    
        public static HungrySingleton getInstance(){
            return SINGLETON;
        }
    
        Object readResolve() throws ObjectStreamException{
            return SINGLETON;
        }
    
    }
    
    public class TestDemo2
    {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
    
            HungrySingleton instance = HungrySingleton.getInstance();
    
            //序列化
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("instance"));
            outputStream.writeObject(instance);
            outputStream.close();
            //反序列化
            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("instance"));
            HungrySingleton readSingleton = (HungrySingleton)inputStream.readObject();
            inputStream.close();
            //比较是否为同一个对象
            System.out.println(instance==readSingleton);
        }
    }
    

    不太懂,之后再研究~~~

    --------------- 我每一次回头,都感觉自己不够努力,所以我不再回头。 ---------------
  • 相关阅读:
    Atitit 经济学常见的流派 古典主义与凯恩斯主义
    Atitit 学习方法 体系化学习方法 Excel 科目,分类,专业 三级分类。。 知识点。。 课程就是每一个知识点的详细化。。 比如经济学 类别 专业 xx概论知识点 3、金
    atiitt it学科体系化 体系树与知识点概念大总结.xlsx
    Atitit 减少财政支出普通人如何蹭政府补贴措施 attilax大总结.docx
    Atitit 信用管理概论 attilax学习心得
    Atitit.月度计划日程表 每月流程表v5
    Atitit 企业6大职能 attilax总结
    Atitit 常见每日流程日程日常工作.docx v8 ver ampm imp 签到 am y 天气情况检查 am y 晨会,每天或者隔天 am 每日计划(项目计划,日计划等。 am
    Atitit 财政赤字解决方案
    Atitit 建设自己的财政体系 attilax总结 1.1. 收入理论 2 1.2. 收入分类 2 1.3. 2 1.4. 非货币收入 2 1.5. 2 1.6. 降低期望 2 1.7.
  • 原文地址:https://www.cnblogs.com/zjw-blog/p/13633974.html
Copyright © 2011-2022 走看看