GOF的23种设计模式(1)—单例模式

单例模式


效果

  • 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
  • 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

分类

常见实现方式

  • 饿汉式:线程安全,调用效率高,不能延时加载。
  • 懒汉式:线程安全,调用效率不高,可延时加载。

其他实现方式

  • 双重检测锁式:由于JVM底层内部模型原因,偶尔出问题,不建议使用。
  • 静态内部类式:线程安全,调用效率高,可延时加载。
  • 枚举单例:线程安全,调用效率高,不能延时加载。

选择方法

  • 单例对象占用资源少,不需要延时加载:枚举式好于饿汉式;
  • 单例对象占用资源多,需要延时加载:静态内部类好于懒汉式。

代码

    //饿汉式单例
    public class Hungry {
        private Hungry() {
        }
        private final static Hungry HUNGRY = new Hungry();
    
        public static Hungry getInstance() {
            return HUNGRY;
        }
    }
    //懒汉式单例
    public class LazyMan {
        //添加标志
        private static boolean tolaris = false;
    
        private LazyMan() {
            //标志判断
            synchronized (LazyMan.class) {
                if (tolaris == false) {
                    tolaris = true;
                } else {
                    throw new RuntimeException("不要试图使用反射破坏异常");
                }
            }
    //        synchronized (LazyMan.class) {
    //            if (lazyMan != null) {
    //                throw new RuntimeException("不要试图使用反射破坏异常");
    //            }
    //        }
        }
       private volatile static LazyMan lazyMan;
        //双重检测锁模式
        private static LazyMan getInstance() {
            if (lazyMan == null) {
                synchronized (LazyMan.class) {
                    if (lazyMan == null) {
                        lazyMan = new LazyMan();//不是原子性操作
                    }
                }
            }
            return lazyMan;
        }
      
        //通过反射破坏
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
            //通过正常的创建
            //LazyMan instance1 = LazyMan.getInstance();
    
            //获取我们设置的标志字段
            Field tolaris = LazyMan.class.getDeclaredField("tolaris");
            tolaris.setAccessible(true);
    
            //获取构造器
            Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
            //无视私有的构造器
            constructor.setAccessible(true);
            //通过反射来创建两个对象
            LazyMan instance1 = constructor.newInstance();
    
            //将第一个对象的值改为false
            tolaris.set(instance1, false);
    
            LazyMan instance2 = constructor.newInstance();
            System.out.println(instance1.hashCode());
            System.out.println(instance2.hashCode());
        }
    }
    //静态内部类
    public class Holder {
        private Holder() {
        }
    
        public static Holder getInstance() {
            return InnerClass.HOLDER;
        }
    
        public static class InnerClass {
            private static final Holder HOLDER = new Holder();
        }
    }
    //枚举
    public enum EnumSingle {
        INSTANCE;
        public EnumSingle getInstance() {
            return INSTANCE;
        }
    }
    class test {
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            EnumSingle instance1 = EnumSingle.INSTANCE;
          //默认不是无参构造器
            Constructor<EnumSingle> constructor =
                    EnumSingle.class.getDeclaredConstructor(String.class,int.class);
            constructor.setAccessible(true);
            EnumSingle instance2 = constructor.newInstance();
            System.out.println(instance1);
            System.out.println(instance2);
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值