• 单例设计模式Singleton


    1.模式定义

    保证一个类只有一个实例,并且提供一个全局访问点

    2.应用场景

    重量级的对象,不需要多个实例,如线程池,数据库连接池。

    2.1 源码中的应用

    1. // Spring & JDK
    2. java.lang.Runtime
    3. org.springframework.aop.framework.ProxyFactoryBean
    4. org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
    5. org.springframework.core.ReactiveAdapterRegistry
    6. // Tomcat
    7. org.apache.catalina.webresources.TomcatURLStreamHandlerFactory
    8. // 反序列化指定数据源
    9. java.util.Currency

    3.实现方式

    3.1 懒汉模式

    延迟加载, 只有在真正使用的时候,才开始实例化。
    1)线程安全问题
    2)double check 加锁优化
    3)编译器(JIT),CPU 有可能对指令进行重排序,导致使用到尚未初始化
    的实例,可以通过添加volatile 关键字进行修饰,
    对于volatile 修饰的字段,可以防止指令重排。
    1. public class LazySingletonTest {
    2. public static void main(String[] args) {
    3. // LazySingleton singleton = LazySingleton.getInstance();
    4. // LazySingleton singleton1 = LazySingleton.getInstance();
    5. // System.out.println(singleton == singleton1);
    6. Thread thread = new Thread(()->{
    7. LazySingleton s1 = LazySingleton.getInstance();
    8. System.out.println(s1);
    9. });
    10. thread.start();
    11. Thread thread2 = new Thread(()->{
    12. LazySingleton s1 = LazySingleton.getInstance();
    13. System.out.println(s1);
    14. });
    15. thread2.start();
    16. }
    17. }
    18. class LazySingleton{
    19. private volatile static LazySingleton singleton = null;
    20. private LazySingleton(){
    21. }
    22. public static LazySingleton getInstance(){
    23. // synchronized 不建议修饰在方法上,因为方法上每次调用都需要加锁,性能低
    24. if (singleton == null) {
    25. synchronized (LazySingleton.class){
    26. if (singleton == null) {
    27. singleton = new LazySingleton();
    28. //字节码
    29. // 1.分配空间
    30. // 2.初始化
    31. // 3.引用赋值
    32. // 初始化和引用赋值可以不分先后进行
    33. }
    34. }
    35. }
    36. return singleton;
    37. }
    38. }

    3.2.饿汉模式

    类加载的 初始化阶段就完成了 实例的初始化 。本质上就是借助于jvm
    类加载机制,保证实例的唯一性(初始化过程只会执行一次)及线程安
    全(JVM以 同步 的形式来完成类加载的整个过程)。
    类加载过程:
    1,加载二进制数据到内存中, 生成对应的Class数据结构,
    2,连接: a. 验证, b.准备(给类的静态成员变量赋 默认值 ),c.解析
    3, 初始化 : 给类的静态变量赋 初值
    只有在真正使用对应的类时,才会触发初始化 如( 当前类是启动类即
    main函数所在类,直接进行new 操作,访问静态属性、访问静态方
    法,用反射访问类,初始化一个类的子类等.)
    1. class HungerSingleton {
    2. private static HungerSingleton singleton = new HungerSingleton();
    3. private HungerSingleton() {
    4. }
    5. public static HungerSingleton getInstance() {
    6. return singleton;
    7. }
    8. }

    3.3 静态内部类

    1).本质上是利用类的加载机制来保证线程安全
    2).只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一
    种形式。
    1. class InnerClassSingleton {
    2. private InnerClassSingleton() {
    3. }
    4. private static class InnerClassHandle {
    5. private static InnerClassSingleton singleton = new InnerClassSingleton();
    6. }
    7. public static InnerClassSingleton getInstance(){
    8. return InnerClassHandle.singleton;
    9. }
    10. }

    3.4 反射攻击实例

    静态内部类防止反射破坏

  • 相关阅读:
    代理设计模式
    01-初识HTML
    Golang关键字-select
    深入理解final关键字
    最近常用的几个【行操作】的Pandas函数
    CAD Exchanger SDK 3.22.0 Crack
    Java中String转List和List转String四种方法
    java框架-Springboot3-场景整合
    CTF-sql注入(X-Forwarded-For)【简单易懂】
    无服务器开发实例|微服务向无服务器架构演进的探索
  • 原文地址:https://blog.csdn.net/xiangbiao2009/article/details/136196711