• 每天一个设计模式之单例模式(六种写法)


    在这里插入图片描述

    基本介绍

    意图

    确保系统内某些类至多只有唯一一个实例。

    典型例子

    1. java.lang.Runtime
    2. java.awt.Desktop

    典型应用

    1. Configuration File
    2. Cache
    3. Logger
    4. drivers
    5. database connection

    UML类图

    在这里插入图片描述

    六种写法

    1. Eager模式

    // 为何final
    class final Singleton extends Serializable {
    	// 一上来就实例化,eagerly;线程安全吗?
        private static Singleton instance = new Singleton();
        private Singleton() { }
    
        public static Singleton getInstance() {
            return instance;
        }
        // 这是什么方法,来自谁?
    	private Object readResolve() throws ObjectStreamException {
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    优点

    1. 简单
    2. 线程安全

    缺点

    1. 类加载时就实例化,性能受到影响;

    补充

    1. 如何保证线程安全?静态成员变量,在类初始化的时候创建,由jvm保证线程安全;
    2. final 的作用?防止子类覆盖父类方法破坏单例;
    3. readResolve 的作用?加入readResolve方法,在反序列化时就会采用 readResolve 返回的对象,而不是反序列化生成的对象,从而防止反序列化破坏单例;

    2. Lazy模式

    class SingletonLazy {
        // 延迟实例化
        private static SingletonLazy instance = null;
        private SingletonLazy() { }
        // 多线程访问会怎样
        public static SingletonLazy getInstance() {
            if (instance == null)
                instance = new SingletonLazy();
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    缺点

    1. 线程不安全;

    3. 非线程安全的Lazy模式

    class SingletonLazySafe {
        // 延迟实例化
        private static SingletonLazySafe instance = null;
        // 有没有什么问题?
        public static synchronized SingletonLazySafe getInstance() {
            if (instance == null)
                instance = new SingletonLazySafe();
            return instance;
        }
    
        private SingletonLazySafe() { }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    优点

    1. 线程安全

    缺点

    1. 即使已经存在实例了,依然需要走同步方法,性能受到影响;

    4. 线程安全的Lazy模式

    class SingletonDoubleCheck {
        // 延迟实例化,volatile 的作用?
        private static volatile SingletonDoubleCheck instance = null;
        public static SingletonDoubleCheck getInstance() {
            if (instance == null) {
                synchronized(SingletonDoubleCheck.class) {
                	// 这一次检查的意义是?
                	if (instance == null)
    	                instance = new SingletonDoubleCheck();
                }
            }
            return instance;
        }
    
        private SingletonDoubleCheck() { }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. volatile 的作用
      防止 SingletonDoubleCheck 在实例化的时候指令重排,导致别的线程获得实例的时候虽不为空,但还未赋值;
    2. 为何要做第二次检查?如果没有第二次检查,如果线程1暂停在 synchronized 外面,线程2在 new SingletonDoubleCheck,那么线程2出去之后,线程1进来,它就又new了一次;
    3. 但是两次检查就安全了吗?还不!因为 new SingletonDoubleCheck() 是一个复合操作;
      初始化对象的过程:
      1) 分配内存
      2) 初始化对象
      3)设置instance指向刚分配的地址
      发生指令重排可能会改变123 的顺序变成132,这时候对象可能还没有初始化完就已经实例化了。
      volatile 关键字有可见性,禁止指令重排的功能。所以距离线程安全就差这一步了;

    5. 基于静态内部类实现单例

    class SingletonStaticInnerClass {
        public static SingletonStaticInnerClass getInstance() {
            return SingletonHolder.instance;
        }
    
        private static class SingletonHolder {
            private static SingletonStaticInnerClass instance = new SingletonStaticInnerClass();
        }
    
        private SingletonStaticInnerClass() { }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    原理

    1. JVM保证只有在调用getInstance的时候才会去加载内部类且初始化单例;

    6. 基于Enum实现单例

    enum  SingletonInEnum {
        INSTANCE;
    
        public void doSomething() {
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    参考:

    1. https://blog.csdn.net/MpenggegeM/article/details/123415319
    2. https://dzone.com/articles/java-singletons-using-enum
    3. https://www.java67.com/2020/05/5-ways-to-implement-singleton-design.html
    4. https://www.geeksforgeeks.org/singleton-design-pattern-introduction/?ref=rp5.

    PLUS - 如果本文对你有帮助,可以随手扫个码,领个包再走!在这里插入图片描述

  • 相关阅读:
    [静态时序分析简明教程(一)] 绪论
    责任链模式
    【STM32HAL库】外部中断
    资源描述框架的用途及实际应用解析
    【TES720D】青翼科技基于复旦微的FMQL20S400全国产化ARM核心模块
    python学习 数据分析模块pandas
    Basic Facilities of a Virtio Device (二)
    F5负载均衡融入新理念,全栈分布式云可持续发展
    python 基础知识点(蓝桥杯python科目个人复习计划58)
    Vue3 - 实现动态获取菜单路由和按钮权限控制指令
  • 原文地址:https://blog.csdn.net/M_sdn/article/details/126222444