目录
一、概述
二、饿汉式
三、懒汉式
3.1 基本实现:
3.2 指令重排
一、概述 什么是单例模式:在整个系统中,每个类仅有一个对象实例
应用场景:
- 业务系统中仅需要一个对象的时候,redis连接对象
- Spring IOC容器中的对象默认是单例的
- 饿汉式:在加载类的时候就创建对象;
- 懒汉式:懒加载模式,在需要获取对象的时候才会创建对象
- 构造方法私有化
- 私有的实例对象
- 对外暴露获取实例对象的方法
public class Singleton {// 饿汉式
private static Singleton singleton = new Singleton();
private Singleton() {
System.out.println("生成一个实例");
}public static Singleton getInstance() {return singleton;
}
}
调用:
public static void main(String[] args) {
new Singleton();
// 编译无法通过
Singleton tareget = Singleton.getInstance();
}
三、懒汉式 实现方面,就是什么时候要获取实例对象,什么时候进行创建; 注意:懒汉式有线程安全问题
3.1 基本实现:
/**
*懒汉式实现
*/
public class SingletonLazy {// 1.私有成员变量,但不直接创建
private SingletonLazy singletonLazy;
// 2.构造函数私有化
private SingletonLazy() {
System.out.println("创建一个对象");
}// 3.对外暴露获取对象的方法
public SingletonLazy getInstance() {
if (singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
return singletonLazy;
}
}
这个实现中,可能存在同时多个线程调用方法,导致最终创建的对象不是同一个,可以使用synchronized解决,但是考虑如果对整个方法上锁,整个执行效率会产生下降,因此应该考虑局部上锁。
而且,这个锁一定上在 if 中,否则和对整个方法上锁没什么区别
// 3.对外暴露获取对象的方法
public SingletonLazy getInstance() {
if (singletonLazy == null) {// 考虑这个部分是否有问题??synchronized (SingletonLazy.class) {
singletonLazy = new SingletonLazy();
}
}
return singletonLazy;
}
看注释的部分,可能存在一个场景:两个线程A, B同时进入 if 中,但是A先获取锁并创建对象,而B在获取锁之后又重新创建了对象,对象发生了变化;
因此,存在一次锁内检查:
// 3.对外暴露获取对象的方法
public SingletonLazy getInstance() {
if (singletonLazy == null) {synchronized (SingletonLazy.class) {
if (singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
}
}
return singletonLazy;
}
结论:双重检测锁定
3.2 指令重排 考虑对象的创建过程:
- 分配空间给对象
- 初始化对象
- 设置对象的内存地址,此时instance != null
产生的现象:而使用 volatile 加载实例对象上,可是保证 变量线程间可见以及禁止指令重排
当第一个线程拿到锁并且进入到第二个if方法后, 先分配对象内存空间, 然后再instance指向刚刚分配的内存地址, instance 已经不等于null, 但此时instance还没有初始化完成。如果这个时候又有一个线程来调用getInstance方法, 在第一个if的判断结果就为false, 于是直接返回还没有初始化完成的instance, 那么就很有可能产生异常。
懒汉式完整实现:
public class SingletonLazy {// 1.私有成员变量,但不直接创建
private volatile SingletonLazy singletonLazy;
// 2.构造函数私有化
private SingletonLazy() {
System.out.println("创建一个对象");
}// 3.对外暴露获取对象的方法
public SingletonLazy getInstance() {
if (singletonLazy == null) {synchronized (SingletonLazy.class) {
if (singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
}
}
return singletonLazy;
}
}
【设计模式~单例模式】
推荐阅读
- spring|2020年Spring全家桶面试题大全含答案共79题
- 设计模式|Java设计模式之简单工厂模式
- android|走穿java23种设计模式-2工厂方法模式详解
- spring|Java最全面试题之Spring篇
- 设计模式|本着什么原则,才能写出优秀的代码()
- JAVA基础知识|java基础知识学习之代理深入学习(用动态代理实现AOP,FacotryBean)
- 设计模式|里氏替换原则(爱恨纠葛的父子关系)
- 前沿技术|一个Tensor在深度学习框架中的执行过程
- 语言|转(我的野蛮成长)