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

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

介绍

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

单例模式特点:

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

单例模式图示如下:

饿汉式

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

java 复制代码
public class SingletonObject {
    private final static SingletonObject obj = new SingletonObject();
    private SingletonObject() {
        System.out.println("创建了单例对象");
    }
    public static SingletonObject getInstance() {
        return obj;
    }
}

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

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

代码实现如下:

java 复制代码
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;
	}
}

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

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

java 复制代码
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;
	}
}

懒汉式---线程不安全

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

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

懒汉式---双重检查锁

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

java 复制代码
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;
    }
}

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

相关推荐
考虑考虑2 小时前
Jpa使用union all
java·spring boot·后端
用户3721574261352 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊3 小时前
Java学习第22天 - 云原生与容器化
java
渣哥5 小时前
原来 Java 里线程安全集合有这么多种
java
间彧5 小时前
Spring Boot集成Spring Security完整指南
java
间彧5 小时前
Spring Secutiy基本原理及工作流程
java
数据智能老司机6 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
Java水解6 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
数据智能老司机7 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
洛小豆9 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试