• 设计模式学习笔记之单例模式


    什么是单例模式? 

    顾名思义,就是只有一个实例,也就是说一个应用程序中只有一个实例对象.

    既然一个系统,一个应用程序中只有一个实例,那么也就说明了如果操作这一个对象,必然涉及到共享资源,涉及到资源分配问题,资源竞争等问题. 

    那么我们的应用场景是什么呢?

    1. 网站的在线人数. 网站的在线人数在某一个时刻,所有人看到的是一样的, 是这个网站这个时刻,所有用户所共享的.

    2. 池化技术. 比如数据库的连接池. 每个数据库的可支持的连接数量是有限,而且连接对象创建和销毁也是比较耗内存的. 通过一个统一的入口去控制,可以保证对数据库的压力在可控的范围内,同是也可以保证出具库连接的持续使用.

    3. 配置中心. 一个应用程序针对通过一个配置文件的加载只需要加载一次即可,不需要多次加载.

    其实以上只是一些常见的应用场景,当然单例模式的应用场景也远不止于此.

    本文参考的博客地址为:https://www.cnblogs.com/mr-yang-localhost/p/9644417.html

    参考的博客的写的很不错, 如果想了解更多,可以去看看这篇参考的博客

    接下来我们来看一下常见的实现方式,以及其中的对比.

     饿汉式,即直接初始化好,使用的时候直接调用即可.

    package com.cbl.design.singletondesign;
    
    public class HungrySingleton {
        private static final HungrySingleton singleton = new HungrySingleton();
    
        //限制外部产生HungrySingleton对象
        private HungrySingleton(){ }
    
        //向外提供获取示例的静态方法
        public static HungrySingleton getInstance() {
            return singleton;
        }
    
    
    }
    

      

    懒汉式, 顾名思义,就是懒,需要的时候再去初始化

    package com.cbl.design.singletondesign;
    
    public class LazySingleton {
        private static volatile LazySingleton singleton = null;
    
        private LazySingleton() { }
    
        public static LazySingleton getSingleton() {
            //不用每次获取对象都强制加锁,为了提升了效率
            if (singleton == null) {
                synchronized (LazySingleton.class) {
                    if (singleton == null) {
                        singleton = new LazySingleton();
                    }
                }
            }
            return singleton;
        }
    }
    

      

    静态内部类的方式

    package com.cbl.design.singletondesign;
    
    public class StaticInnerSingleton {
        /**
         * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
         * 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
         */
        private static class Singleton2Holder {
            /**
             * 静态初始化器,由JVM来保证线程安全
             */
            private static StaticInnerSingleton singleton = new StaticInnerSingleton();
        }
    
        private StaticInnerSingleton() {
            //System.out.println("singleton2 private construct method called");
        }
    
        public static StaticInnerSingleton getSingleton() {
            //System.out.println("singleton2 getSingleton method called");
            return Singleton2Holder.singleton;
        }
    
        private String name;
    
        public void desc() {
            //System.out.println("singleton2 desc method called");
        }
    }
    

      

    还有一种实现方式是依赖于枚举, 我们知道枚举中的对象是实例化好的,而且枚举天生要求枚举类的构造器必须私有,而且本身还是被final 修饰的, 不可被继承

    package com.cbl.design.singletondesign;
    
    public enum EnumSingleton {
        INSTANCE;
    
        public String getDesc() {
            return "desc";
        }
    
        public static void process() {
            System.out.println("static process method");
        }
    
        private String name;
        private Integer age;
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
    }
    

      

    以上是4中常见的构造单例模式的四种线程安全的构造单例的设计模式.网上可能还有其余的非线程安全的构建单例的方法, 但是线程安全的主要就是这四种.

    (1) : 饿汉式 :  加载类的时候就会进行实例化,,如果后续没有用到,则会搞成资源浪费.

    (2) : 懒汉式 : 使用的时候再去初始化,这样在前几次调用并发调用的时候,会出现资源竞争, 等待时间较久,但是后续再次调用的时候, 由于是双重判断加加锁校验机制, 不会出现阻塞.

    (3): 静态内部类 : 也是在使用的时候再去加载内部类并初始化外部类的对象,第一次调用会比较慢.

    (4):枚举单例:  类加载的时候就穿创建好对象了, 特点和饿汉式很像.

    上面是这几种单例方式的特点,其中懒汉式,饿汉式,静态内部类的方式都不能防止反射,只有枚举类可以防止反射.

    但是一般我们的应用程序只需要保证可以正常实现单例即可,没必要过多的去防止单例模式,我们使用单例模式,就是想构造单例对象的,但是我们自己又去使用反射去破坏单例模式,这不是自己给自己找麻烦吗.

  • 相关阅读:
    解释器模式
    命令模式
    责任链模式
    代理模式
    享元模式
    外观模式
    装饰器模式
    组合模式
    过滤器模式
    js广告浮动
  • 原文地址:https://www.cnblogs.com/cheng21553516/p/12008579.html
Copyright © 2020-2023  润新知