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


    在这里插入图片描述

    基本介绍

    意图

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

    典型例子

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

  • 相关阅读:
    Java.lang.Class类 getGenericInterfaces()方法有什么功能呢?
    金仓数据库KingbaseES数据库参考手册(服务器配置参数9. 错误报告和日志)
    各种编程语言对比一览
    Spark常用算子
    Chrome 基于 Wappalyzer 查看网站所用的前端技术栈
    第八章 贪心
    Android ListView的使用方法
    iNavFlight之MSP Sensor报文格式
    【Java】详解SimpleDateFormat的format方法和parse方法
    Linux下最新版MySQL 8.0的下载与安装(详细步骤)
  • 原文地址:https://blog.csdn.net/M_sdn/article/details/126222444