• 设计模式-单例模式


    单例模式

    保证一个类只有一个实例,并提供一个访问该实例的全局节点。

    为啥要保证一个类只有一个实例?

    如控制某些共享资源的访问权限,例如数据库或文件;
    如为避免频繁创建一个可复用的对象,需要仅在首次时初始化;

    怎么保证一个类只有一个实例?

    懒汉式

    静态内部类

    巧妙利用Java类加载机制,保证多线程环境下的线程安全性。当一个类被加载时,其静态内部类是不会同时被加载的,只有第一次被调用时才会初始化,而且不能通过反射的方式获取内部的属性。

    public class Singleton{
    	private Singleton(){}
    
        public static Singleton getInstance(){
            return SingletonInstance.instance;
        }
    
        private static class SingletonInstance{
            private static final Singleton instance = new Singleton();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    双重检锁

    在多线程环境下,为了提高实例初始化的性能,不是每次获取实例时在方法上加锁,而是当实例未创建时才会加锁。
    这里使用volatile对instance进行修饰,是因为volatile禁止指令重排,保证了线程安全性。
    创建一个对象的步骤非原子操作,大致可以分为3部分,
    (1)给instance分配内存
    (2)调用实例Singleton的构造函数初始化instance
    (3)将instance指向分配的内存地址
    在多线程情况下,假设A线程执行创建instance的操作,对于B线程有俩种状态,(1)(2)下为null, (3)下为非null;在创建对象不是一个原子操作的前提下,CPU为提高运行效率,可能会对3个操作进行指令重排,如果重排后指令执行顺序是1,3,2,那么B线程获取到instance状态。是未赋值下的状态,即可能是null
    volatile禁止指令重排,通过添加读屏障和写屏障,保证在该变量不会把其后面的指令重排到内存屏障之前,不会把其前面的指令重排到内存屏障之后。

    public class Singleton{
    	private volatile static Singleton instance;
    
        public static Singleton getInstance(){
            if(instance == null){
                synchronized(this){
                    if(instance == null){
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    饿汉式

    类加载的时候就创建实例,使用私有构造函数实现全局单个实例的初始化,并使用public static final修饰,实现延迟加载和保证线程安全性。

    public class Singleton{
        private static final Singleton instance = new Singleton();
    
        private Singleton(){}
    
        public static Singleton getInstance(){
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    枚举式

    它能够保证序列化和反序列化过程中实例的唯一性,而且不用担心线程安全问题。

    public enum Singleton {
    
        SERVICE_A {
    
            @Override
    
            protected void hello() {
    
                System.out.println("hello, service A");
    
            }
    
        },
    
        SERVICE_B {
    
            @Override
    
            protected void hello() {
    
                System.out.println("hello, service B");
    
            }
    
        };
    
        protected abstract void hello();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    参考链接

    单例设计模式
    Netty中的设计模式
    Java并发编程

  • 相关阅读:
    c++ 回调函数,std::function,std::bind
    Redis 常用的数据结构简介与实例测试【Redis 系列二】
    计算机毕业设计选什么题目好?springboot 学生考勤管理系统
    docker 实战
    mysql 数据去重的三种方式[实战]
    Java面试题大全(整理版)1000+面试题附答案详解最全面看完稳了
    10:00面试,10:04就出来了 ,问的实在是太...
    iOS 全平台矢量动画库:体积小巧、功能丰富 | 开源日报 No.227
    100天精通Python(基础篇)——第21天:if elif嵌套
    Android Banner - ViewPager 02
  • 原文地址:https://blog.csdn.net/qq_34732050/article/details/128089403