import java.util.HashMap;
import java.util.Map;
/**
* @author The one
* @date 2021-09-06 09:11
* @describe 单例模式 - 创造型
* @email 625805189@qq.com
* @remark 1.构造方法不是公开的,一般是private
* 2.通过一个静态的方法或者枚举返回单例对象
* 3.注意多线程场景
* 4.单例类对象在反序列化时不会重新创建对象
*/
public class SingletonPattern {
/**
* 懒汉式
* TODO 开销比较大,希望用到时才创建就要考虑延迟实例化 Singleton的初始化需要某些外部资源(比如网络或存储设备)
*/
static class Singleton1{
/**
* 私有的构造方法
*/
private Singleton1(){}
/**
* 私有的静态变量
* static修饰的变量以s开头命名
* [volatile] JDK 1.5 -> 防止指令重排
*/
private volatile static Singleton1 sInstance = null;
/**
* 暴露一个公开的获取单列的方法
*/
public static Singleton1 getInstance(){
// DCL 双重校验
// 第一层校验
if(null == sInstance){
synchronized (Singleton1.class){
// 第二层校验
if(null == sInstance){
sInstance = new Singleton1();
// 上面这句代码会执行以下指令
// 1. sInstance实例分配对象
// 2. 调用Singleton1的构造方法,初始化成员变量
// 3. Singleton1对象赋值给sInstance
// JDK -> 指令重排,三个步骤可能乱序,会导致双重校验失效
}
}
}
return sInstance;
}
}
/**
* 恶汉模式
*
* TODO 应用程序总是创建并使用单例实例或在创建和运行时开销不大
*/
static class Singleton2{
private Singleton2(){}
/**
* 类加载的时候单例就已经被加载了
*/
private static Singleton2 sInstance = new Singleton2();
public static Singleton2 getInstance(){
return sInstance;
}
}
/**
* 静态类部类
*/
static class Singleton3{
private static class Holder{
/**
* 第一次虚拟机加载Singleton3对象时,sInstance 并不会被初始化
*/
private static final Singleton3 sInstance = new Singleton3();
}
/**
* 调用此方法时, Holder.sInstance 才会被初始化。做到了延迟加载。
*/
public static Singleton3 getInstance(){
return Holder.sInstance;
}
}
/**
* 枚举默认是线程安全的,任何情况下都是单例的
*/
static class Singleton4{
private Singleton4(){}
enum SingleEnum{
INSTANCE;
private Singleton4 single;
private SingleEnum (){
single = new Singleton4();
}
public Singleton4 getSingle(){
return single;
}
}
public static Singleton4 getInstance(){
return SingleEnum.INSTANCE.getSingle();
}
}
/**
* 单例管理器
*/
static class SingletonManager{
private final static Map<String,Object> OBJ_MAP = new HashMap<>();
public static void registerService(String key,Object instance){
if(!OBJ_MAP.containsKey(key)){
OBJ_MAP.put(key,instance);
}
}
public static Object getService(String key){
return OBJ_MAP.get(key);
}
}
}