单例模式:
* 确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例
* 有2种创建方式:懒汉模式 、饿汉模式
1)恶汉模式:在类加载时就创建好了对象,而不是在用到时候创建
# 由ClassLoad保证线性安全
public class HungrySingleton {
private static HungrySingleton hungrySingleton = new HungrySingleton();
/**
* 私有化构造函数,不能被外部访问
*/
private HungrySingleton() {}
/**
* 返回单例对象
*/
public static HungrySingleton getHungrySingleton() {
return hungrySingleton;
}
}
2)懒汉模式:在第一次使用该对象时创建
--> 有问题的代码:线性不安全
public class LazySingleton {
private static LazySingleton lazySingleton = null;
/**
* 私有化构造函数,不能被外部访问
*/
private LazySingleton() {}
/**
* 返回单例对象
*/
public static LazySingleton getlazySingleton() {
if(lazySingleton == null){
return new LazySingleton();
}
return lazySingleton;
}
}
–> 改进:
双重锁检查:在加锁之前先判断 对象 == null 是否成立,如果不成立直接返回创建的,成立就加锁
public class LazyDoubleCheckSingleton {
/**
* 使用volatile进行修饰,禁止指令重排
*/
private static volatile LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
/**
* 私有化构造函数,不能被外部访问
*/
private LazyDoubleCheckSingleton() {}
/**
* 返回单例对象
*/
public static LazyDoubleCheckSingleton getLazyDoubleCheckSingleton() {
if(lazySingleton == null){
synchronized(LazyDoubleCheckSingleton.class){
if(lazySingleton == null){
return new LazyDoubleCheckSingleton();
}
}
}
return lazyDoubleCheckSingleton;
}
}
说明:
为什么需要对 lazyDoubleCheckSingleton 添加 volatile 修饰符
因为 lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton(); 不是原子性的,分为三步:
1) 为lazyDoubleCheckSingleton分配内存
2) 调用构造函数进行初始化
3) 将lazyDoubleCheckSingleton对象指向分配的内存【执行完这步 lazyDoubleCheckSingleton 将不为 null 】
为了提高程序的运行效率,编译器会进行一个指令重排,步骤2和步骤三进行了重排,线程1先执行了步骤一和步骤三,
执行完后,lazyDoubleCheckSingleton不为null,此时线程2执行到if (lazyDoubleCheckSingleton == null),
线程2将可能直接返回未正确进行初始化的lazyDoubleCheckSingleton对象。出错的原因主要是lazyDoubleCheckSingleton未正确初始化完成【写】,
但是其他线程已经读取lazyDoubleCheckSingleton的值【读】,使用volatile可以禁止指令重排序,通过内存屏障保证写操作之前不会调用读操作【执行if (lazyDoubleCheckSingleton == null)】
缺点 为了保证线程安全,代码不够优雅过于臃肿
-->改进:静态内部类
public class LazyStaticSingleton {
/**
* 静态内部类
* */
private static class LazyStaticSingletonHolder {
private static LazyStaticSingleton lazyStaticSingleton = new LazyStaticSingleton();
}
/**
* 构造函数私有化
* */
private LazyStaticSingleton() {
}
public static LazyStaticSingleton getLazyStaticSingleton() {
return LazyStaticSingletonHolder.lazyStaticSingleton;
}
}