定义
单例模式是指在内存中有且只会创建一次对象的设计模式,在程序中多次使用同一个对象且作用相同的时候,为了防止频繁的创建对象,单例模式可以让程序在内存中创建一个对象,让所有的调用者都共享这一单例对象。单例模式的类型有两种:懒汉式和饿汉式。
使用场景
1、业务系统全局只需要⼀个对象实例,⽐如序号生成器、redis连接对象等
2、Spring IOC容器中的bean默认就是单例
3、spring boot 中的controller、service、dao层中通过@autowire的依赖注⼊对象默认都是单例的
分类
懒汉:就是所谓的懒加载,延迟创建对象
饿汉:与懒汉相反,提前创建对象
如何选择
饿汉⽅式:提前创建好对象
优点:实现简单,没有多线程同步问题
缺点:不管有没使⽤,instance对象⼀直占着这段内存
如果对象不⼤,且创建不复杂,直接⽤饿汉的⽅式即可;其他情况则采⽤懒汉实现⽅式
实现步骤
1、私有化构造函数
2、提供获取单例的⽅法
懒汉模式代码实现(最后一种是用于实践)
第一种方式
public class SingletonLazy {
private static SingletonLazy instance;
/**
* 构造函数私有化
*/
private SingletonLazy(){}
/**
* 单例对象的方法
*/
public void process(){
System.out.println("方法调用成功");
}
/**
* 第一种方式
* 对外暴露一个方法获取类的对象
*
* 线程不安全,多线程下存在安全问题
*
*/
public static SingletonLazy getInstance(){
if(instance == null){
instance = new SingletonLazy();
}
return instance;
}
}
使用方调用
SingletonLazy.getInstance().process();
第二种方式
public class SingletonLazy {
private static SingletonLazy instance;
/**
* 构造函数私有化
*/
private SingletonLazy(){}
/**
* 单例对象的方法
*/
public void process(){
System.out.println("方法调用成功");
}
/**
* 第二种实现方式
* 通过加锁 synchronized 保证单例
*
* 采用synchronized 对方法加锁有很大的性能开销
*
* 解决办法:锁粒度不要这么大
*
* @return
*/
public static synchronized SingletonLazy getInstance(){
if(instance == null){
instance = new SingletonLazy();
}
return instance;
}
}
使用方调用
SingletonLazy.getInstance().process();
第三种方式
public class SingletonLazy {
private static SingletonLazy instance;
/**
* 构造函数私有化
*/
private SingletonLazy(){}
/**
* 单例对象的方法
*/
public void process(){
System.out.println("方法调用成功");
}
/**
* 第三种实现方式
*
* DCL 双重检查锁定 (Double-Checked-Locking),在多线程情况下保持高性能
*
* 这是否安全,instance = new SingletonLazy(); 并不是原子性操作
* 1、分配空间给对象
* 2、在空间内创建对象
* 3、将对象赋值给引用instance
*
* 假如线程 1-》3-》2顺序,会把值写会主内存,其他线程就会读取到instance最新的值,但是这个是不完全的对象
* (指令重排)
* @return
*/
public static SingletonLazy getInstance(){
if(instance == null){
// // A、B
synchronized (SingletonLazy.class){
if(instance == null) {
instance = new SingletonLazy();
}
}
}
return instance;
}
}
使用方调用
SingletonLazy.getInstance().process();
第四种
public class SingletonLazy {
private static volatile SingletonLazy instance;
/**
* 构造函数私有化
*/
private SingletonLazy(){}
/**
* 单例对象的方法
*/
public void process(){
System.out.println("方法调用成功");
}
/**
* volatile是Java提供的关键字,它具有可见性和有序性,
*
* 指令重排序是JVM对语句执行的优化,只要语句间没有依赖,那JVM就有权对语句进行优化
*
* 禁止了指令重排
*/
public static SingletonLazy getInstance(){
//第一重检查
if(instance == null){
// A、B ,锁定
synchronized (SingletonLazy.class){
//第二重检查
if(instance == null) {
instance = new SingletonLazy();
}
}
}
return instance;
}
}
使用方调用
SingletonLazy.getInstance().process();
饿汉模式代码实现
public class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry(){}
public static SingletonHungry getInstance(){
return instance;
}
/**
* 单例对象的方法
*/
public void process(){
System.out.println("方法调用成功");
}
}
使用方调用
SingletonHungry.getInstance().process();