单例模式总结

📅 2026/7/28 20:05:03
单例模式总结
单例模式最常见的有两种单例模式饿汉式和懒汉式如下/** * 饿汉式 */ public class SingletonHungry { //单例对象 private SingletonHungry instance new SingletonHungry(); //私有构造方法 private SingletonHungry(){} public SingletonHungry getInstance(){ return instance; } }/** *懒汉式 */ public class SingletonLazy { //单例对象 private static SingletonLazy instance; //私有构造方法 private SingletonLazy(){} //静态工厂方法 public static SingletonLazy getInstance(){ if(instancenull){ instance new SingletonLazy(); } return instance; } }上述两种方式都存在着线程不安全的情况以懒汉式为例instance对象还没创建的时候如果两条线程访问getInstance方法进入了if条件同时都new的话就产生了两个实例。解决方案synchronized加双重检测/** *synchronized加双重检测 */ public class SingletonSyn { //单例对象 private static SingletonSyn instance; //私有构造函数 private SingletonSyn(){} //静态工厂方法 public static SingletonSyn getInstance(){ //双重检测 if(instance null){ synchronized (SingletonSyn.class){ if(instancenull){ instance new SingletonSyn(); } } } return instance; } }解析双重检测的好处就是首先判断instance为空有两条线程都可以进入了这判断条件当一条线程执行完了getInstance方法释放了锁 然后另一条线程已经进入第一层判断这时可获取锁如果在synchronized代码块不做判断就有产生了一个实例就不是单例了存在问题此时仍难不是线程安全的因为JVM会进行指令重排new一个对象的步骤是1.分配对象的内存空间2.初始化对象3.设置instance指向刚分配的实例 *有些时候JVM会把其顺序条为1323过程执行了对象就不等于null所以就存在下边这种情况线程A在new对象线程B在第一个条件判断 * 当线程A先执行了13此时线程B刚好判断为false那么线程B直接返回instance这是一个没创建好的对象所以就出错了解决方案单例加上volatile关键字防止指令重排/** *线程安全的单例代码 */ public class SingletonSyn { //单例对象 private volatile static SingletonSyn instance; //私有构造函数 private SingletonSyn(){} //静态工厂方法 public static SingletonSyn getInstance(){ //双重检测 if(instance null){ synchronized (SingletonSyn.class){ if(instancenull){ instance new SingletonSyn(); } } } return instance; } }存在问题此时还会存在一个问题我们能利用反射仍可获得多个对象解决办法用枚举类/** * 枚举类实现单例模式 */ public enum SingletonEnum { INSTANCE; private SingletonEnum() { } public void print(){ System.out.println(hello world); } } public static void main(String[] args) { SingletonEnum instance SingletonEnum.INSTANCE; instance.print(); }至此单例一些情况全都介绍完了