设计模式–单例
参考链接
https://www.bilibili.com/video/BV1pt4y1X7kt?spm_id_from=333.337.search-card.all.click&vd_source=3efcb41ebc2977a53fbbea093c7df1b6
整个运行时域,一个类只有一个实例对象。
有的类的实例对象创建和销毁对资源消耗不大。
数据库连接对象,只创建一次并重复使用这个对象。
如何实现单例模式
1 是否线程安全
2 是否懒加载
3 是否反射破坏
懒加载
public class Singleton{
private Singleton(){} //构造器私有
private static Singleton instance =null; //初始化对象为空
public static Singleton getInstance(){
if(instance==null){
instance=new Sinleton();
}
return instance;
}
}
//实例对象是第一次被调用时才构造。只有真正使用了才去创建
明显的,此时线程不安全,因为判断实例对象是否空时候可能同时进入多个线程,实例化多次。
优化1
加上synchronized
public class Singleton{
private Singleton(){} //构造器私有
private static Singleton instance =null; //初始化对象为空
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Sinleton();
}
return instance;
}
}
只想要对象在构建时候同步,上面的写法,每次获取对象时都需要进行同步操作。严重影响性能
优化2
编译器构建 ;但是此时并不是懒加载,先不处理这个。
public class Singleton{
private static Singleton instance =new Singleton();
public static Singleton getInstance(){
return instance;
}
}
优化3
getInstance不竞争锁,只有在实例化时候加锁。
争抢锁,抢到的进行构建,
若已经构建,直接返回,。
问题,虽然只有一个线程执行语句3,但是可能有其他线程已经进入if代码块,还是会导致对象还是会被创建多次。
public class Singleton{
private static Singleton singleton;
privcate Singleton(){}
public static Singleton getSingleton(){
if(singleton==null){//2
synchronized(Singleton.class){//3
singleton=new Singleton();
}
}
return singleton;//若已经构建,直接返回
}
}
优化4
a线程执行完毕释放锁,b拿到锁,但是会进行判空,此时实例不空,直接退出并返回实例。
public class Singleton{
private static Singleton singleton;
privcate Singleton(){}
public static Singleton getSingleton(){
if(singleton==null){
synchronized(Singleton.class){
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
volatile可以解决作用在instance上指令重排问题。happens-before情况
优化5
双检锁写法
public class Singleton{
private volatile static Singleton singleton;
privcate Singleton(){}
public static Singleton getSingleton(){
if(singleton==null){
synchronized(Singleton.class){
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}