设计模式之单例模式

单例模式

懒汉模式

懒汉模式即延迟加载,在需要用到该实例时进行实例化,在使用懒汉模式需要注意以下几点

  • synchronized线程安全
  • double check 保证只有一个线程创建成功
  • 使用volatile禁止编译器对对象在实例化的过程中进行重排序
public class LazySingleton {

    private volatile static LazySingleton singleton;

    public static LazySingleton getLazySingleton() {
        if (singleton == null) {
            synchronized (LazySingleton.class) {
                if (singleton == null) {
                    // 1.分配内存
                    // 2.初始化
                    // 3.引用赋值
                    singleton = new LazySingleton();
                }
            }
        }
        return singleton;
    }
}

实例化对象并不是原子操作,可以分为三个步骤:

  • 分配内存;
  • 初始化对象
  • 将内存地址赋值给引用
    编译器在不影响程序执行结果的情况下,会对以上步骤进行指令重排序,可能将第二步和第三步进行替换;如果t1刚执行完第三步,准备执行第二步,此时t2进来判断singleton不为空,直接返回没有初始化的对象,导致程序异常。

饿汉模式

饿汉模式通过jvm类加载器实现的,在加载类时的初始化阶段就完成了类的初始化(即初始化阶段给类的静态变量赋值)。并且类加载器由双亲委派机制使用保证只会被加载一次,并且loadClass在加载类时使用synchronized保证线程安全

public class HungrySingleton {

    private static HungrySingleton singleton = new HungrySingleton();

    private HungrySingleton() {
        //防止反射攻击
        if (HungrySingleton.singleton != null) {
            throw new RuntimeException("单例不允许创建多个实例");
        }
    }

    public static HungrySingleton getSingleton() {
        return singleton;
    }

	public static void main(String[] args) throws Exception {
        HungrySingleton singleton = HungrySingleton.getSingleton();
        //反射攻击实例
        Constructor<HungrySingleton> constructor = HungrySingleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        HungrySingleton instance = constructor.newInstance();
        System.out.println(instance == singleton);
    }
}

静态内部类

  • 本质上是利用类的加载机制来保证线程安全
  • 只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一种形式。
public class InnerClassSingleton {

    private static class InnerClassHolder {
        private static InnerClassSingleton singleton = new InnerClassSingleton();
    }

    private InnerClassSingleton() {
        if (InnerClassHolder.singleton != null) {
            throw new RuntimeException("单例不允许创建多个实例");
        }
    }

    public static InnerClassSingleton getSingleton() {
        return InnerClassHolder.singleton;
    }
}

枚举类型

  • 天然不支持反射,且有自己的序列化机制
  • 利用类加载机制保证线程安全
public enum EnumSingleton {

    INSTANCE;
}

反序列化

指定方法来替换在反序列化创建的实例
比如在静态内部类实现的单例模式中添加如下方法

	Object readResolve() {
        return InnerClassHolder.singleton;
    }

应用场景

源码级应用场景

  • 饿汉模式:java.lang.Runtime
private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}
}
  • 懒汉模式:org.springframework.core.ReactiveAdapterRegistry
public static ReactiveAdapterRegistry getSharedInstance() {
		ReactiveAdapterRegistry registry = sharedInstance;
		if (registry == null) {
			synchronized (ReactiveAdapterRegistry.class) {
				registry = sharedInstance;
				if (registry == null) {
					registry = new ReactiveAdapterRegistry();
					sharedInstance = registry;
				}
			}
		}
		return registry;
	}
  • 反序列化时一个id对应一个实例org.springframework.beans.factory.support.DefaultListableBeanFactory.SerializedBeanFactoryReference
private Object readResolve() {
			Reference<?> ref = serializableFactories.get(this.id);
			if (ref != null) {
				Object result = ref.get();
				if (result != null) {
					return result;
				}
			}
			// Lenient fallback: dummy factory in case of original factory not found...
			DefaultListableBeanFactory dummyFactory = new DefaultListableBeanFactory();
			dummyFactory.serializationId = this.id;
			return dummyFactory;
		}

日常开发应用场景

  • 线程池对象
  • 工厂对象

相关推荐

  1. 【前端设计模式模式

    2024-03-24 05:34:02       63 阅读
  2. 设计模式模式

    2024-03-24 05:34:02       57 阅读
  3. C++设计模式模式

    2024-03-24 05:34:02       58 阅读
  4. 设计模式模式

    2024-03-24 05:34:02       54 阅读
  5. 设计模式模式

    2024-03-24 05:34:02       63 阅读
  6. 设计模式模式

    2024-03-24 05:34:02       53 阅读
  7. 【软件设计模式模式

    2024-03-24 05:34:02       57 阅读
  8. c++设计模式模式

    2024-03-24 05:34:02       47 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-24 05:34:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-24 05:34:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-24 05:34:02       87 阅读
  4. Python语言-面向对象

    2024-03-24 05:34:02       96 阅读

热门阅读

  1. 面试宝典:MySQL-深度分析如何避免幻读

    2024-03-24 05:34:02       39 阅读
  2. 第4周 Python程序流程控制刷题(循环结构)

    2024-03-24 05:34:02       38 阅读
  3. Gin简介(Go web基础知识)

    2024-03-24 05:34:02       40 阅读
  4. oracle ADG主备切换

    2024-03-24 05:34:02       45 阅读
  5. Spring设计模式-实战篇之策略模式 + 工厂模式

    2024-03-24 05:34:02       47 阅读
  6. Android studio 简单入门程序

    2024-03-24 05:34:02       35 阅读
  7. 《过滤器模式(极简c++)》

    2024-03-24 05:34:02       46 阅读
  8. 快速入门Kotlin②控制流&函数

    2024-03-24 05:34:02       47 阅读
  9. kotlin中使用myibatis-plus的lambdaQuery的问题

    2024-03-24 05:34:02       32 阅读
  10. 数学,2549. 统计桌面上的不同数字

    2024-03-24 05:34:02       40 阅读