六种单例模式(Java实现)
最简单的设计模式,目的是保证全局访问它的一个唯一实例。
六种实现方式
-
饿汉模式
//饿汉模式 public class EHan { private static EHan instance = new EHan(); private EHan(){} public static EHan getInstance(){ return instance; } }
是线程安全的
存在的问题:产生了不必要的内存占用
-
懒汉模式
//懒汉模式 public class LHan { private static LHan instance; private LHan(){} public static LHan getInstance(){ if(instance == null){ instance = new LHan(); } return instance; } }
延迟加载,没有产生内存垃圾
存在的问题:不是线程安全的
-
加锁模式(线程安全的懒汉式)
public class LHan { private static LHan instance; private LHan(){} //加了锁 public static synchronized LHan getInstance(){ if(instance == null){ instance = new LHan(); } return instance; } }
lazy loading
存在的问题:锁的粒度太大,效率大大降低
-
双重校验锁模式
//双重校验锁模式 public class DoubleCheck { private volatile static DoubleCheck instance; private DoubleCheck(){} public static DoubleCheck getInstance(){ if(instance == null){ //提高效率性 A B synchronized (DoubleCheck.class){ if(instance == null){ //保证准确性 instance = new DoubleCheck(); 1.分配空间 2.空间初始化 3.instance指向空间 //volatile其中一个功能是禁止指令重排 } } } return instance; } }
两个判断的作用
存在的问题:
-
静态内部类
public class Singleton { private Singleton(){ } public static Singleton getInstance(){ return SingletonHolder.instance; } private static class SingletonHolder { private static final Singleton instance = new Singleton(); } }
静态内部类 的加载属于懒汉加载
Singleton.getInstance();
lazy loading
-
枚举
public enum Singleton { INSTANCE; public void whateverMethod() { } }
总结:建议使用静态内部类的方式,不建议使用懒汉模式(包括加锁的),可以使用饿汉模式,如果有反序列化的场景建议使用枚举的方式,明确要求延时加载(lazy loading)可以使用双重校验锁