【设计模式】单例模式

【设计模式】单例模式

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();
  • 优点:绝对单例(防止反射/序列化破坏)

  • 缺点:不够灵活

各实现方式对比

实现方式 延迟加载 线程安全 性能 防反射 防序列化
饿汉式
懒汉式
同步方法懒汉式 低(频繁加锁)
双重检查锁定 较高
静态内部类
枚举
相关推荐
高山上有一只小老虎6 分钟前
idea中设置快捷键风格
java·ide·intellij-idea
JH30737 分钟前
IDEA自带的Maven安装位置
java·maven·intellij-idea
梵得儿SHI31 分钟前
Java 反射机制核心类详解:Class、Constructor、Method、Field
java·开发语言·反射·class·constructor·java反射·java反射机制
m0_7369270442 分钟前
想抓PostgreSQL里的慢SQL?pg_stat_statements基础黑匣子和pg_stat_monitor时间窗,谁能帮你更准揪出性能小偷?
java·数据库·sql·postgresql
Jabes.yang44 分钟前
Java面试大作战:从缓存技术到音视频场景的探讨
java·spring boot·redis·缓存·kafka·spring security·oauth2
Query*1 小时前
Java 设计模式——适配器模式进阶:原理深挖、框架应用与实战扩展
java·设计模式·适配器模式
Sirens.1 小时前
Java核心概念:抽象类、接口、Object类深度剖析
java·开发语言·github
Meteors.1 小时前
23种设计模式——中介者模式 (Mediator Pattern)详解
java·设计模式·中介者模式
望获linux1 小时前
【实时Linux实战系列】使用 u-trace 或 a-trace 进行用户态应用剖析
java·linux·前端·网络·数据库·elasticsearch·操作系统
焰火19991 小时前
[Java]基于Spring的轻量级定时任务动态管理框架
java·后端