Emove

  • 首页
  • 归档
  • 分类
  • 标签

  • 搜索
context 反射 channel LRU BeanDefinition JVM 装饰者模式 MyBatis 快慢指针 归并排序 链表 hash表 栈 回溯 贪心 主从复制 二分查找 双指针 动态规划 AOF RDB 规范 BASE理论 CAP B树 RocketMQ Sentinel Ribbon Eureka 命令模式 访问者模式 迭代器模式 中介者模式 备忘录模式 解释器模式 状态模式 策略模式 职责链模式 模板方法模式 代理模式 享元模式 桥接模式 外观模式 组合模式 适配器模式 建造者模式 原型模式 工场模式 单例 UML 锁 事务 sql 索引

单例模式

发表于 2020-04-04 | 分类于 设计模式 | 18 | 阅读次数 145

所谓类的单例设计模式、就是采取一定的方法保证在整个的软件系统中、对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。

例如:Hibernate中的SessionFactory对象,它充当数据存储源的代理,并且负责创建Session对象,SessionFactory并不是轻量级的,一般情况下,一个项目通常值需要一个SessionFactory就足够,这时就会使用到单例模式。

  • 饿汉式(静态常量)

    class SingletonStaticConst {
        // 私有化构造器
        private SingletonStaticConst() {
    
        }
    
        // 本类内部创建对象实例
        private final static SingletonStaticConst instance = new SingletonStaticConst();
    
        // 提供共有静态方法返回实例对象
        public static SingletonStaticConst getInstance() {
            return instance;
        }
    }
    
    • 构造器私有化
    • 类的内部创建对象
    • 向外暴露一个静态公共方法

    优点:

    1. 在类装载时完成实例化。避免了线程同步问题

    缺点:

    1. 在类装载时就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费
    2. 这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法,但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法),导致类装载,这时候初始化instance就没有达到Lazy Loading的效果、
    3. 结论:这种单例模式可用,但可能造成内存浪费
  • 饿汉式(静态代码块)

    class SingletonStaticBlock {
    
        private SingletonStaticBlock() {
    
        }
    
        private static SingletonStaticBlock instance;
    
        static {
            // 在静态代码块中创建单例对象
            instance = new SingletonStaticBlock();
        }
    
        public static SingletonStaticBlock getInstance() {
            return instance;
        }
    }
    

    静态代码块的实例化方式和常量实例化方式类似,只不过将类的实例化过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。优缺点与上面的方式一致。(单线程模式下推荐使用)

  • 懒汉式(线程不安全)

    class Singleton {
    
        private static Singleton instance;
    
        private Singleton() {
    
        }
    
        // 提供一个静态的公有方法,当使用到该方法时,才去创建instance
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    优缺点:

    1. 起到了Lazy Loading的效果,但是只能在单线程下使用
    2. 如果在多线程环境下, 一个线程进入了if(instance == null)判断语句块中,还未来得及往下执行,另外一个线程叶通过了这个判断语句,这时便会产生多个实例,所有在多线程环境下不可使用这中方式
    3. 在实际开发中不要使用这中方式
  • 懒汉式(线程安全、同步方法)

    class SingletonSynchroMethod {
    
        private static SingletonSynchroMethod instance;
    
        private SingletonSynchroMethod () {
    
        }
    
        /**
         * 在每次调用这个方法时,都要进行同步,效率较低
         * @return
         */
        public static synchronized SingletonSynchroMethod getInstance() {
            if (instance == null) {
                instance = new SingletonSynchroMethod();
            }
            return instance;
        }
    
    }
    

    优缺点:

    1. 解决了线程不安全问题
    2. 效率太低了,每个线程在想获得类的实例的时候,执行getInstance方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面想获得该类实例,直接return就行了,方法进行同步效率太低。在实际开发中不推荐使用这种方法
  • 懒汉式(线程不安全、同步代码块)

    class SingletonSynchroBlock {
    
        private static SingletonSynchroBlock instance;
    
        private SingletonSynchroBlock() {
    
        }
    
        /**
         * 这种方法实际上并不能实现同步的效果,当有两个线程都进入if判断语句块时,虽然进行了同步锁,但是执行只是时间问题
         * @return
         */
        public static SingletonSynchroBlock getInstance() {
            if (instance == null) {
                synchronized (SingletonSynchroBlock.class) {
                    instance = new SingletonSynchroBlock();
                }
            }
            return instance;
        }
    }
    

    优缺点:

    1. 这种同步代码块的实现方法并不能实现同步作用,假如一个线程进入了if判断语句块,还没来得及往下执行,另一个线程也通过了if判断语句,这时便会产生多个实例
    2. 在实际开发中不能使用这种 方法
  • 双重检查

    class DoubleCheckSingleton {
    
        private static volatile DoubleCheckSingleton instance;
    
        private DoubleCheckSingleton() {
    
        }
    
        public static DoubleCheckSingleton getInstance() {
            if (instance == null) {
                synchronized (DoubleCheckSingleton.class) {
                    if (instance == null) {
                        instance = new DoubleCheckSingleton();
                    }
                }
            }
            return instance;
        }
    
    }
    

    优缺点:

    1. Double-Check概念是多线程开发中常使用到的,在实现懒加载的同时,也保证了线程安全
    2. 在实例的创建中,只要对象已经初始化,就可以避免反复的进行方法同步
    3. 总结:线程安全,延迟加载,效率较高,在实际开发中,推荐使用这种方式
  • 静态内部类

    class InnerClassSingleton {
    
        private InnerClassSingleton() {
    
        }
    
        private static class InnerClassSingletonInstance{
            private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
        }
    
        public static InnerClassSingleton getInstance() {
            return InnerClassSingletonInstance.INSTANCE;
        }
    
    }
    

    优缺点:

    1. 这种方式采用了类装载的机制来保证初始化实例时只有一个线程
    2. 静态内部类方式在InnerClassSingleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载InnerClassSingletonInstance类(静态内部类),从而完成Singleton的实例化
    3. 类的静态属性只会在第一次加载类的时候初始化,所以这种方法利用了JVM的装载机制来保证线程的安全性(在类进行初始化时,别的线程时无法进入的)
    4. 避免了线程安全问题,利用静态内部类特点实现延迟加载,效率高
  • 枚举

    enum EnumSingleton {
        /**
         * 示例
         */
        INSTANCE("Emove","123456");
    
        private EnumSingleton(String userName, String password) {
            this.userName = userName;
            this.password = password;
        }
    
    	/** 这两个字段只是做个演示,在实际开发中,可以是任何的属性 **/
        private String userName;
        private String password;
    
        public String getUserName() {
            return this.userName;
        }
    
        public String getPassword() {
            return this.password;
        }
    }
    

    优缺点:

    1. 不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
    2. 这种方式是Effective Java坐着Josh Bloch提倡的方式

Runtime单例源码(饿汉式)

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    private Runtime() {}
    }

单例模式注意事项和细节说明:

  • 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
  • 当想实例化一个单例类的时候,必须要记住使用相应的获取方法而不是使用new
  • 单例模式使用场景,需要频繁的进行创建和销毁的对象,创建对象时耗时过多或耗费系统资源过多(即:重量级对象),但又经常用到的对象,工具类对象,频繁访问数据库或文件的对象(比如数据源、session工厂等)
# context # 反射 # channel # LRU # BeanDefinition # JVM # 装饰者模式 # MyBatis # 快慢指针 # 归并排序 # 链表 # hash表 # 栈 # 回溯 # 贪心 # 主从复制 # 二分查找 # 双指针 # 动态规划 # AOF # RDB # 规范 # BASE理论 # CAP # B树 # RocketMQ # Sentinel # Ribbon # Eureka # 命令模式 # 访问者模式 # 迭代器模式 # 中介者模式 # 备忘录模式 # 解释器模式 # 状态模式 # 策略模式 # 职责链模式 # 模板方法模式 # 代理模式 # 享元模式 # 桥接模式 # 外观模式 # 组合模式 # 适配器模式 # 建造者模式 # 原型模式 # 工场模式 # 单例 # UML # 锁 # 事务 # sql # 索引
职责链模式
微服务架构
  • 文章目录
  •   |  
  • 概览
林亦庭

林亦庭

less can be more

87 文章
11 分类
54 标签
RSS
Github
Creative Commons
© 2021 林亦庭
粤ICP备20029050号