一 模式定义
保证一个类只有一个实例,并提供一个全局访问点
二 场景
之所以使用单例模式,是因为某些重量级的对象,不需要多个实例,因为占用系统资源过高。例如线程池,数据库连接池。
三 两种经典模式
1.懒汉模式
只有在对象使用时才初始化。
举例代码如下:
/**
* @author xionglz
* @Slogan 致敬大师,致敬未来的你
*/
class LazySingleton{
//使用valatitle防止指令重排序,不使用可能造成空指针异常。
private volatile static LazySingleton instance;
/*私有构造函数防止其他类创建实例*/
private LazySingleton(){
}
public static LazySingleton getInstance() {
//每次初始化前先判断是否为空
if (instance==null){
//使用java内置锁保证线程安全
synchronized (LazySingleton.class){
//双重检查防止重复创建对象保证单例,因为第二个线程拿到锁后,此时对象可能已经创建
if (instance==null){
/*
创建对象非原子操作JIT可能会进行指令重排,所以需用valatitle
创建对象顺序为:
1.分配空间
2.初始化
3.引用赋值
*/
instance=new LazySingleton();
}
}
}
return instance;
}
}
2.饿汉模式
在类加载的初始化阶段就完成了实例的创建。本质上是利用了jvm的类加载机制保证实例的唯一性。
类加载过程:
只有在真正使用对应的类时才会触发初始化。例如启动类所在函数,直接进行new 操作,访问静态属性,静态方法,用反射访问一个类,初始化一个类的子类。
代码如下
class HungrySingleton{
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton(){
//防止反射创建实例
if (HungrySingleton.instance != null) {
throw new RuntimeException( " 不允许多个实例。" );
}
}
public static HungrySingleton getInstance() {
return instance;
}
}
四 枚举类型
1.天然不支持反射获取实例
2.通过jvm类加载机制实现