• 设计模式—创建型模式之单例模式


    设计模式—创建型模式之单例模式

    介绍

    单例模式说明:一个单一的类,负责创建自己的对象,同时确保系统中只有单个对象被创建。

    单例模式特点:

    1. 某个类只能有一个实例;(构造器私有)
    2. 它必须自行创建这个实例;(自己编写实例化逻辑)
    3. 它必须自行向整个系统提供这个实例;(对外提供实例化方法)

    单例模式图示如下:

    单例模式图

    饿汉式

    饿汉式,比较简单,代码如下:

    public class SingletonObject {
        private final static SingletonObject obj = new SingletonObject();
        private SingletonObject() {
            System.out.println("创建了单例对象");
        }
        public static SingletonObject getInstance() {
            return obj;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    懒汉式—效率低下实现方式1(线程安全

    获取实例的方法是static的,我们可以给整个方法加一个锁,这样锁的对象是整个类,可以保证线程安全:

    代码实现如下:

    public class SingletonObject {
    	//懒汉式
    	private static SingletonObject obj;
    	//保证构造器私有,外部不能实例化
    	private SingletonObject() {
    		System.out.println("创建了单例对象");
    	}
    	//这种锁粒度太大,导致效率低
    	public static synchronized SingletonObject getInstance() {
    		//懒汉式,如果没有再去创建
    		if(obj == null) {
    			obj = new SingletonObject();
    		}
    		return obj;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    懒汉式—效率低下实现方式2(线程安全)

    我们可以不给整个方法加锁,可以给如下代码块加锁,但是这样的方式效率还是低;

    public class SingletonObject {
    	//懒汉式
    	private static SingletonObject obj;
    	//保证构造器私有,外部不能实例化
    	private SingletonObject() {
    		System.out.println("创建了单例对象");
    	}
    	//但是这样锁粒度还是太大,进入到方法里边再加锁,这样效率还低
    	public static SingletonObject getInstance() {
    		synchronized(SingletonObject.class) {
    			//懒汉式,如果没有再去创建
    			if(obj == null) {
    				obj = new SingletonObject();
    			}
    		}
    		return obj;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    懒汉式—线程不安全

    我们能否在创建时再加锁呢,于是有了如下的代码:

    public class SingletonObject {
    	//懒汉式
    	private static SingletonObject obj;
    	//保证构造器私有,外部不能实例化
    	private SingletonObject() {
    		System.out.println("创建了单例对象");
    	}
    	//线程不安全
    	public static SingletonObject getInstance() {
    		//懒汉式,如果没有再去创建
    		if(obj == null) {
    			synchronized(SingletonObject.class) {
    				obj = new SingletonObject();
    			}
    		}
    		return obj;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这样的方式是线程不安全的,比如:

    1. 有两个线程,线程1和线程2都进入到方法中,判断到obj为null;
    2. 假如线程1先获取到锁,为obj赋值完成,然后方法运行结束,返回obj;
    3. 然后线程2获取到锁,又把obj赋值一次;此时两次返回的就不是同一个对象了。

    懒汉式—双重检查锁

    下面的懒汉式设计模式,用了双重检查锁;

    public class SingletonObject {
        //懒汉式,线程可见性
        private volatile static SingletonObject obj;
        //首先保证构造器私有,外部不能实例化
    
        private SingletonObject() {
            System.out.println("创建了单例对象");
        }
        /**
         * 双重检查锁 + 内存可见性volatile
         */
        public static SingletonObject getInstance() {
            //懒汉式,如果没有再去创建
            if (obj == null) {
                synchronized (SingletonObject.class) {
                    if(obj == null){
                        obj = new SingletonObject();
                    }
                }
            }
            return obj;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    方法getInstance()中,如果单例对象为空,才会把方法块加锁,获取到锁的线程创建对象完成并赋值成功,且obj保证了线程可见性,其他线程便可以感知到obj不为null,就不会再创建赋值了。

  • 相关阅读:
    MyBatisPlus枚举类最佳实践(非常典型和高效的枚举类写法)
    python学习之基本语法---语法规则---函数的基本用法(三)day9
    掌握C语言文件操作:从入门到精通的完整指南!
    MySQL数据库 —— 常用语句
    解决Error in rawToChar(block[seq_len(ns)]) :
    用树莓派PICO做一个桌面时钟超详细教程!
    win环境安装Node.js的多种方式
    基于Java毕业设计智能超市导购系统源码+系统+mysql+lw文档+部署软件
    中级程序员——uniapp和小程序面试题
    Mac opencv 摄像头权限
  • 原文地址:https://blog.csdn.net/qq_41243472/article/details/134064508