设计模式-单例模式

单例模式 (Singleton Pattern)是一种常用的设计模式,确保一个类在整个应用程序中只有一个实例,并且提供一个全局访问点来访问这个实例。它的主要目标是控制实例化,避免创建多个实例,以节省资源并保证全局状态的一致性。

在Java中实现单例模式有几种常见的方式:

1. 懒汉式单例(Lazy Initialization Singleton)

实现方式

懒汉式单例是在需要时才创建实例 (即延迟加载)。这是通过在首次调用 getInstance() 方法时创建对象的。

java 复制代码
public class LazySingleton {
    // 私有静态实例,尚未初始化
    private static LazySingleton instance;

    // 私有构造函数,防止外部实例化
    private LazySingleton() {}

    // 提供获取实例的全局访问点
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();  // 在第一次调用时创建实例
        }
        return instance;
    }
}
优点
  • 实例在需要时才创建,节省资源。
  • 延迟加载,避免程序启动时不必要的实例创建。
缺点
  • 线程不安全 :如果有多个线程同时访问 getInstance(),可能会导致多个实例被创建。需要进行额外的线程同步处理。

2. 线程安全的懒汉式单例

为了解决懒汉式单例的线程安全问题,可以在 getInstance() 方法上加上同步锁。

java 复制代码
public class SynchronizedLazySingleton {
    private static SynchronizedLazySingleton instance;

    private SynchronizedLazySingleton() {}

    // 通过 synchronized 关键字保证线程安全
    public static synchronized SynchronizedLazySingleton getInstance() {
        if (instance == null) {
            instance = new SynchronizedLazySingleton();
        }
        return instance;
    }
}
优点
  • 保证了线程安全,不会出现多个实例。
缺点
  • 每次调用 getInstance() 都会进行同步操作,可能会导致性能瓶颈,特别是在多线程环境中,大量调用时性能下降明显。

3. 双重检查锁定(Double-Checked Locking)

为了解决同步性能问题,可以使用"双重检查锁定"技术。只在实例为空时才加锁,避免每次调用都进行同步。

java 复制代码
public class DoubleCheckedSingleton {
    private static volatile DoubleCheckedSingleton instance;

    private DoubleCheckedSingleton() {}

    public static DoubleCheckedSingleton getInstance() {
        if (instance == null) {  // 第一次检查
            synchronized (DoubleCheckedSingleton.class) {
                if (instance == null) {  // 第二次检查
                    instance = new DoubleCheckedSingleton();
                }
            }
        }
        return instance;
    }
}
关键点
  • volatile 关键字:确保多个线程正确处理实例变量的可见性。
  • 双重检查:通过在同步块内外都进行 null 检查,避免不必要的同步操作。
优点
  • 线程安全,同时避免了不必要的同步,提高了性能。
缺点
  • 实现较为复杂,理解起来有一定的难度。

4. 饿汉式单例(Eager Initialization Singleton)

实现方式

饿汉式单例是在类加载时就创建实例,而不是在需要时才创建。这是通过直接初始化静态变量来实现的。

java 复制代码
public class EagerSingleton {
    // 类加载时就创建实例
    private static final EagerSingleton instance = new EagerSingleton();

    // 私有构造函数,防止外部实例化
    private EagerSingleton() {}

    // 提供获取实例的全局访问点
    public static EagerSingleton getInstance() {
        return instance;
    }
}
优点
  • 简单,类加载时即创建实例,线程安全。
  • 没有锁机制,性能高。
缺点
  • 不具备延迟加载特性,可能会在程序不需要该实例时就加载,浪费资源。

5. 静态内部类实现单例(Static Inner Class Singleton)

这种方式利用了Java类加载机制中的延迟加载特性。静态内部类只有在第一次被使用时才会被加载,从而实现懒加载的效果。

java 复制代码
public class InnerClassSingleton {
    private InnerClassSingleton() {}

    // 静态内部类,只有在被调用时才会装载
    private static class SingletonHolder {
        private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }

    public static InnerClassSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
原理
  • 静态内部类 SingletonHoldergetInstance() 方法被调用时才会加载,因此实现了延迟加载。
  • 类加载机制保证了线程安全性。
优点
  • 延迟加载,线程安全,且实现简单。
  • 不需要加锁,性能优越。
缺点
  • 和饿汉式类似,加载时耗费时间,如果实例初始化很大,会带来一些性能损耗。

6. 枚举单例(Enum Singleton)

枚举类型是实现单例模式最简单且安全的方法,它不仅避免了反序列化破坏单例,还能防止反射攻击。

java 复制代码
public enum EnumSingleton {
    INSTANCE;

    public void doSomething() {
        System.out.println("Do something...");
    }
}
优点
  • 简单明了,Java语言本身提供了枚举的特性,保证了实例的唯一性。
  • 线程安全且可以防止序列化和反射攻击。
缺点
  • 枚举单例无法懒加载。

总结

单例模式在需要控制某个类的全局唯一实例时非常有用,比如数据库连接池、线程池、配置管理等场景。选择哪种实现方式取决于具体的需求:

  • 懒汉式:适合希望延迟加载的场景,但需要考虑线程安全问题。
  • 饿汉式:适合在类加载时就需要实例的场景,但无法延迟加载。
  • 双重检查锁定:适合需要线程安全且有一定性能要求的场景。
  • 静态内部类:实现了懒加载且线程安全,推荐使用。
  • 枚举:最简单且安全的实现方式,防止序列化和反射攻击,但无法延迟加载。
相关推荐
找不到、了2 分钟前
Java设计模式之适配器模式
java·设计模式·适配器模式
小猫咪怎么会有坏心思呢9 分钟前
华为OD机考-生成哈夫曼树-二叉树(JAVA 2025B卷)
java·开发语言·华为od
翱翔的小菜鸟35 分钟前
Java Stream API中peek()方法使用不当引发的生产问题
java·开发语言
xcs1940536 分钟前
java 导入数据和数据验证处理方案
java·linux·python
哪吒编程1 小时前
我的第一个AI编程助手,IDEA最新插件“飞算JavaAI”,太爽了
java·后端·ai编程
Code季风1 小时前
SQL关键字三分钟入门:WITH —— 公用表表达式让复杂查询更清晰
java·数据库·sql
沿着缘溪奔向大海2 小时前
蓝牙数据通讯,实现内网电脑访问外网电脑
java·爬虫·python·socket·蓝牙
过期动态2 小时前
MySQL中的常见运算符
java·数据库·spring boot·mysql·spring cloud·kafka·tomcat
想用offer打牌2 小时前
一站式了解责任链模式
java·后端·设计模式·责任链模式
专注VB编程开发20年2 小时前
C# .NET多线程异步记录日声,队列LOG
java·开发语言·前端·数据库·c#