单例模式
确保只有单个对象被创建,提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化类对象。属于创建型模式
单例模式创建
1.饿汉式
线程安全,缺点很明显 初始化时就会被创建,占用内存
public class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return instance;
}
}
2.懒汉式
简易版:线程不安全
public class LazySingleton {
private LazySingleton(){}
private static LazySingleton lazySingleton;
public static LazySingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
升级版:对方法加锁,但是会影响效率
public class LazySingletonPlus {
private LazySingletonPlus(){}
private static LazySingletonPlus lazySingletonPlus;
public static synchronized LazySingletonPlus getInstance(){
if(lazySingletonPlus == null){
lazySingletonPlus = new LazySingletonPlus();
}
return lazySingletonPlus;
}
}
3.DCL double-check-lock 双重锁校验
/**
* 线程安全
* 线程安全的懒加载的升级版
*
* 第一次校验,对象还没生成 如果此时有第二个线程想要获取 那么会被锁拦住 但是他只是被拦在锁外面
* 对象生成完毕后 锁释放,第二个线程进入,此时需要再判断一下是否为空
*
* 为什么使用volatile?
* 禁止指令重排序。因为在对象生成过程中,可能存在指令重排序,
* 1、分配内存空间
* 2、属性赋值
* 3、将dclsingleton指向该内存空间
*
* 当发生指令重排时,最终结果是一致的,但是对于dcl来讲
* 假设现在 第一个线程的对象创建 1、3 先完成,此时 已经指向内存空间,那么第二个线程就会判断不为空,直接拿走了。
* 获取到了一个没有属性赋值的对象
*/
public class DCLSingleton {
private DCLSingleton(){}
private static volatile DCLSingleton dclSingleton;
public static DCLSingleton getInstance(){
if(dclSingleton == null){
synchronized (DCLSingleton.class){
if(dclSingleton == null){
dclSingleton = new DCLSingleton();
}
}
}
return dclSingleton;
}
}