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

    设计模式2——单例模式

    饿汉式:

    package com.ghl.single;
    
    /**
    * @ProjectName DesignPattern
    * @ClassName Hungry
    * @Date 2020/8/25 15:42
    * @Author gaohengli
    * @Version 1.0
    */
    //饿汉式单例
    public class Hungry {
    
        //可能会浪费空间
        private byte[] data1=new byte[1024*1024];
        private byte[] data2=new byte[1024*1024];
        private byte[] data3=new byte[1024*1024];
        private byte[] data4=new byte[1024*1024];
    
        //私有化构造函数
        private Hungry() {
        }
    
        //设立静态变量,直接创建实例
        private static final Hungry HUNGRY = new Hungry();
    
        //开放公有方法,判断是否已存在实例
        public static Hungry getInstance(){
            return HUNGRY;
        }
    }
    

    懒汉式:

    package com.ghl.single;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    
    /**
    * @ProjectName DesignPattern
    * @ClassName LazyMan
    * @Date 2020/8/25 16:01
    * @Author gaohengli
    * @Version 1.0
    */
    //DCL懒汉式单例
    public class LazyMan {
    
        private static boolean flag = false;
    
        //私有化构造器
        private LazyMan() {
            /*//解决反射破坏单例的问题
            synchronized (LazyMan.class) {
                if (lazyMan != null) {
                    throw new RuntimeException("不要试图用反射破坏异常");
                }
            }*/
    
            synchronized (LazyMan.class) {
                if (flag==false){
                    flag=true;
                }else {
                    throw new RuntimeException("不要试图用反射破坏异常");
                }
            }
        }
    
        //volatile可见性,禁止指令重排序
        private volatile static LazyMan lazyMan;
    
        //双重检测锁模式的懒汉式单例,DCL懒汉式
        public static LazyMan getInstance() {
            if (lazyMan == null) {
                synchronized (LazyMan.class) {
                    if (lazyMan == null) {
                        lazyMan = new LazyMan();//不是一个原子性操作
                        /*
                        1.分配内存空间
                        2.执行构造方法,初始化对象
                        3.把这个对象执行这个空间
                         */
                    }
                }
            }
            return lazyMan;
        }
    
        /*//多线程并发
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                new Thread(()->{
                    LazyMan.getInstance();
                }).start();
            }
        }*/
    
        //反射,会破坏单例
        public static void main(String[] args) throws Exception {
            //LazyMan instance = LazyMan.getInstance();
    
            Field flag = LazyMan.class.getDeclaredField("flag");
            flag.setAccessible(true);
    
            Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
            declaredConstructor.setAccessible(true);//破坏私有权限
    
            LazyMan instance = declaredConstructor.newInstance();
    
            flag.set(instance,false);
    
            LazyMan instance1 = declaredConstructor.newInstance();
    
            System.out.println(instance);
            System.out.println(instance1);
        }
    }
    

    静态内部类:

    package com.ghl.single;
    
    /**
    * @ProjectName DesignPattern
    * @ClassName Holder
    * @Date 2020/8/25 17:10
    * @Author gaohengli
    * @Version 1.0
    */
    //静态内部类实现
    public class Holder {
    
        private Holder(){
    
        }
    
        public static Holder getInstance(){
            return InnerClass.HOLDER;
        }
    
        //静态内部类
        public static class InnerClass{
            private static final Holder HOLDER=new Holder();
        }
    }
    

    *前面的单例模式都不安全,因为反射可以破解,因此下面使用枚举。

    枚举单例模式:

    package com.ghl.single;
    
    
    import java.lang.reflect.Constructor;
    
    
    /**
    * @ProjectName DesignPattern
    * @ClassName EnumSingle
    * @Date 2020/8/25 17:35
    * @Author gaohengli
    * @Version 1.0
    */
    //enum,枚举,本身也是一个Class类
    public enum EnumSingle {
    
        INSTANCE;
    
        public EnumSingle getInstance(){
            return INSTANCE;
        }
    }
    
    
    class Test{
        public static void main(String[] args) throws Exception {
            EnumSingle instance = EnumSingle.INSTANCE;
    
            //Exception in thread "main" java.lang.NoSuchMethodException: com.ghl.single.EnumSingle.<init>()
            //Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
            Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
    
            declaredConstructor.setAccessible(true);
            EnumSingle instance1 = declaredConstructor.newInstance();
    
            System.out.println(instance);
            System.out.println(instance1);
        }
    }
    

    检测枚举时结果会报Exception in thread "main" java.lang.NoSuchMethodException。出现这个异常的原因是因为EnumSingleton.class.getDeclaredConstructors()获取所有构造器,会发现并没有我们所设置的无参构造器,只有一个参数为(String.class,int.class)构造器,而且在反射在通过newInstance创建对象时,会检查该类是否ENUM修饰,如果是则抛出异常,反射失败。所以枚举是不怕发射攻击的。

    枚举有有参构造函数。枚举不怕反射的攻击。

  • 相关阅读:
    C++中的动态内存管理
    Harbor镜像仓库搭建
    nexus私服搭建
    Tekton ACK安装
    容器监控实践,从入门到放弃
    Bitwarden_搭建密码服务器
    Jenkins-部署文档
    Mysql-基本的
    Zabbix添加-钉钉故障报警
    ZABBIX-4.4 yum安装
  • 原文地址:https://www.cnblogs.com/ghlz/p/13564492.html
Copyright © 2011-2022 走看看