【设计模式】单例模式

【设计模式】单例模式

1、什么是单例模式

单例模式(Singleton): 保证整个系统中一个类仅有一个对象实例,并提供一个可以访问它的全局访问点。

  • 为什么要设计单例模式?单例模式的优点体现在哪些方面?

    单例模式的设计保证了一个类在整个系统中同一时刻只有一个实例存在,主要被用于一个全局类的对象在多个地方被使用并且对象的状态是全局变化的场景下。同时,单例模式为系统资源的优化提供了很好的思路,频繁创建和销毁对象都会增加系统的资源消耗,而单例模式保障了整个系统只有一个对象能被使用,很好地节约了资源。

2、单例模式实现

🎍2.1 饿汉式(线程安全)

原理:在类加载时就创建实例

java 复制代码
 //饿汉式
 public class HungrySingleton {
     private static HungrySingleton instance = new HungrySingleton();
     private HungrySingleton(){}
     public static HungrySingleton getInstance(){
         return instance;
     }
 }

类中直接定义全局的静态对象的实例并初始化,然后提供一个方法获取该实例对象。优点是实现简单,并且线程安全,缺点也很明显,比如在代码中没有使用这个对象也会创建出一个实例,可能会造成资源浪费。

🍔2.2 懒汉式(线程不安全)

原理:首次使用时才创建实例

java 复制代码
public class LazySingleton {
    private static LazySingleton instance;
    
    private LazySingleton() {}
    
    public static LazySingleton getInstance() {
        if (instance == null) {
            // 多线程可能同时进入此区域
            instance = new LazySingleton();
        }
        return instance;
    }
}

做法和饿汉式基本差不多,只是在返回实例对象时加入判断,如果已经创建,直接返回创建好的实例对象,确保首次使用才创建。不过需要注意的是,在进行判断时,多线程情况下的其他线程也可能会进入判断,导致线程不安全。优点是延迟加载,需要用到才会创建,一旦创建就一直使用已经创建好的实例,改善了饿汉式的缺点。

🍪2.3 同步方法懒汉式 (线程安全)

原理:通过方法级同步保证线程安全

java 复制代码
public class SyncMethodSingleton {
    private static SyncMethodSingleton instance;
    
    private SyncMethodSingleton() {}
    
    // 方法同步保证线程安全
    public static synchronized SyncMethodSingleton getInstance() {
        if (instance == null) {
            instance = new SyncMethodSingleton();
        }
        return instance;
    }
}

和懒汉式唯一的区别在于获取实例对象方法被synchronized 关键字修饰,相当于锁住整个类对象,同一时刻只允许一个线程进入方法,防止多线程情况下创建多个实例

  • 优点:实现简单且线程安全
  • 缺点:性能差(每次调用都同步)

🏇2.4 双重检查锁定

原理:减少同步范围 + volatile禁止指令重排序

java 复制代码
public class DCLSingleton {
    // volatile保证可见性和禁止指令重排序
    private static volatile DCLSingleton instance;
    
    private DCLSingleton() {}
    
    public static DCLSingleton getInstance() {
        if (instance == null) { // 第一次检查(无锁)
            synchronized (DCLSingleton.class) {
                if (instance == null) { // 第二次检查(有锁)
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}

第一次if(instance==null):为了提高代码的执行效率,由于单例模式只要一次创建实例即可,所以当创建了一个实例之后,再次调用getInstance方法就不同进入同步代码块,不用竞争锁。

第二次if(instance==null):这个校验时防止二次创建实例。

  • 优点:高性能线程安全

  • 缺点:实现较复杂

1.为什么用 volatile
  • 禁止指令重排序

    instance = new Singleton()实际分为三步:

    1.分配内存空间

    2.初始化对象

    3.将引用指向内存地址

    若无 volatile,JVM 可能重排序为 1→3→2。此时其他线程可能拿到未初始化的对象(instance != null但对象不完整)。

  • 内存可见性 :确保所有线程看到最新的 instance值。

2.双重检查的必要性
  • 第一次检查:避免每次访问都加锁(性能优化)。
  • 第二次检查:防止多个线程同时通过第一次检查后重复创建实例。

🚗2.5 静态内部类(线程安全)

原理:利用类加载机制保证线程安全

java 复制代码
public class HolderSingleton {
    private HolderSingleton() {}
    
    // 静态内部类
    private static class SingletonHolder {
        private static final HolderSingleton INSTANCE = new HolderSingleton();
    }
    
    public static HolderSingleton getInstance() {
        // 首次调用时加载内部类
        return SingletonHolder.INSTANCE;
    }
}

静态内部类方式利用JVM类加载机制 确保线程安全,同时实现懒加载 特性(延迟初始化)。核心原理是:静态内部类不会在外部类加载时初始化,只有在显式调用时才会加载

  • 优点:延迟加载 + 无同步开销

  • 缺点:无法防止反射攻击

🎠2.6 枚举单例

原理:使用一个只包含单个元素的枚举类型来实现单例模式。

java 复制代码
public enum EnumSingleton {
    // 唯一实例
    INSTANCE;
    
    // 添加逻辑方法
    public void doSomething() {
        System.out.println("枚举单例方法");
    }
}

// 使用方式
EnumSingleton.INSTANCE.doSomething();
  • 优点:绝对单例(防止反射/序列化破坏)

  • 缺点:不够灵活

各实现方式对比

实现方式 延迟加载 线程安全 性能 防反射 防序列化
饿汉式
懒汉式
同步方法懒汉式 低(频繁加锁)
双重检查锁定 较高
静态内部类
枚举
相关推荐
Asmalin11 小时前
【代码随想录day 22】 力扣 40.组合总和II
java·算法·leetcode
FrankYoou12 小时前
Spring MVC + JSP 项目的配置流程,适合传统 Java Web 项目开发
java·spring·springmvc
七夜zippoe12 小时前
AI 赋能 Java 开发效率:全流程痛点解决与实践案例(一)
java·开发语言·人工智能
翻斗花园刘大胆12 小时前
JavaSE之String 与 StringBuilder 全面解析(附实例代码)
java·开发语言·jvm·git·java-ee·intellij-idea·html5
Poppy .^0^12 小时前
Tomcat 全面指南:从目录结构到应用部署与高级配置
java·tomcat
一 乐12 小时前
在线宠物用品|基于vue的在线宠物用品交易网站(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·|在线宠物用品交易网站
shepherd11112 小时前
深入解析Flowable工作流引擎:从原理到实践
java·后端·工作流引擎
l56575812 小时前
第五十天(SpringBoot栈&Actuator&Swagger&HeapDump&提取自动化)
java·spring boot·spring
荣淘淘12 小时前
互联网大厂Java面试三大回合全解析:从语言特性到性能安全
java·安全·面试·性能优化·互联网·多线程·语言特性
给力学长12 小时前
洗衣店小程序的设计与实现
java·数据库·vue.js·小程序·node.js