设计模式四:单例模式(Singleton)

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。

通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。

要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,"阻止"所有想要生成对象的访问。

单例模式的分类

单例模式可以根据实现方式的不同,分为以下几种分类:

  1. 饿汉式(Eager Initialization):在类加载的时候就创建并初始化单例对象。这种方式简单直接,线程安全,但可能会造成资源浪费,因为即使没有使用单例对象,它也会被提前创建。
  2. 懒汉式(Lazy Initialization):在第一次使用时创建单例对象。这种方式避免了不必要的资源浪费,但需要考虑线程安全性,确保在多线程环境下仍然能够正确地创建单例对象。
  3. 双重检验锁(Double-Checked Locking):结合了懒汉式和饿汉式的优点,在多线程环境下既能保证线程安全,又能延迟单例对象的创建。这种方式通过加锁来控制并发访问,并使用 volatile 关键字来保证可见性。
  4. 静态内部类(Static Inner Class):利用类加载机制来实现延迟加载和线程安全的单例对象。通过定义一个私有的静态内部类,在这个静态内部类中创建单例对象,从而保证只有在第一次使用时才会触发单例对象的初始化。
  5. 枚举(Enum):枚举类型本身就是单例的。在Java中,枚举类型能够保证在任何情况下都只有一个实例。因此,可以直接使用枚举来实现单例模式。
    这些分类方式基本上涵盖了常见的单例模式实现方式。根据具体的需求和场景,选择适合的单例模式实现方式可以提高代码的可靠性和性能效率。

Singleton模式的使用场景

单例模式是一种常见的设计模式,在以下情况下可以考虑使用单例模式:

1.全局资源共享:当应用程序需要在多个部分共享同一个资源时,可以使用单例模式确保只有一个实例存在。例如,数据库连接池、日志记录器等全局资源可以使用单例模式来管理和访问。

2.对象缓存:当需要缓存对象以提高性能时,可以使用单例模式来管理缓存。通过保持单例实例,可以避免重复创建对象,并且在需要时可以快速获取缓存对象。

3.配置信息管理:当应用程序需要维护一些全局配置信息时,可以使用单例模式来管理这些配置。这样可以确保只有一个实例保存和管理配置信息,并且可以在程序的各个地方使用。

4.日志记录器:在应用程序中,通常需要一个日志记录器来记录系统的操作和异常信息。通过使用单例模式,可以方便地在代码的任何地方访问和使用统一的日志记录器。

5.系统计数器:某些场景需要记录系统某些操作的次数,如请求处理次数、任务处理次数等。使用单例模式可以方便地实现对统计数据的更新和访问。

需要注意的是,单例模式并不适用于所有的场景。在一些情况下,它可能会导致代码的复杂性增加,或者造成不必要的性能开销。

饿汉式

指全局的单例实例在类装载时构建。它是线程安全的,但是如果这个类我一直不使用,由于类初始化时,就已经实例它了,所以它会一直占着资源不释放。

java 复制代码
/**
 * 单例模式
 */
public class Singleton {
    // 饿汉式
    private static Singleton instance2 = new Singleton();
    public static Singleton getInstance3(){
        return instance2;
    }
}

懒汉式--线程不安全

最基础的实现方式,线程上下文单例,不需要共享给所有线程,也不需要加synchronize之类的锁,以提高性能,有个致命缺点,就是在两个相同的线程中同时调用了getInstance1() 时,就会在这两个线程中产生不同的Singleton 对象。单例的作用就相当没有了。由于它的线程不安全,所以有了下面的方式。

java 复制代码
/**
 * 单例模式
 */
public class Singleton {
    private static Singleton instance;
    // 懒汉式---线程不安全
    public static Singleton getInstance1(){
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

懒汉式--线程安全

加上synchronize之类保证线程安全的基础上的懒汉模式,相对性能很低,大部分时间并不需要同步。

java 复制代码
/**
 * 单例模式
 */
public class Singleton {
    private static Singleton instance;
    // 懒汉式---线程安全
    public static synchronized Singleton getInstance2(){
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

它是线程安全了;但由于它是同步方法,在多线程调用它时,都会synchronized下,从而效率低下。在使用的过程中为了提高效率,所以我们有了如下方式

双重检验锁

在懒汉式基础上利用synchronize关键字和volatile关键字确保第一次创建时没有线程间竞争而产生多个实例,仅第一次创建时同步,性能相对较高

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

    private Singleton() {
        // 私有构造函数,防止外部创建实例
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

在上述代码中,getInstance() 方法使用了双重检验锁,首先检查 instance 是否为 null,如果是,则再进入同步块进行二次检查,确保只有一个线程能够创建实例。同时,为了避免由于指令重排序而导致的问题,需要给 instance 声明为 volatile,保证可见性。

静态内部类(登记式)

创建类的全局属性存在,创建类被装载时创建。

java 复制代码
public class Singleton {
    private static Map<String, Singleton> registry = new HashMap<>();
    
    private Singleton() {
        // 私有构造函数,防止外部实例化
    }
    
    public static synchronized Singleton getInstance(String key) {
        if (!registry.containsKey(key)) {
            registry.put(key, new Singleton());
        }
        return registry.get(key);
    }
}

第一次记载Singleton 时并不会初始化instance,只有第一次调用getInstance4()时才会实例化。它不仅保证线程安全、也能保证对象的唯一性,同时也延迟了单例的实例化。它也是最为推荐的一种单例模式

相关推荐
槿花Hibiscus3 小时前
C++基础:Pimpl设计模式的实现
c++·设计模式
吾与谁归in3 小时前
【C#设计模式(4)——构建者模式(Builder Pattern)】
设计模式·c#·建造者模式
shinelord明3 小时前
【再谈设计模式】建造者模式~对象构建的指挥家
开发语言·数据结构·设计模式
matrixlzp9 小时前
Java 责任链模式 减少 if else 实战案例
java·设计模式
编程、小哥哥11 小时前
设计模式之组合模式(营销差异化人群发券,决策树引擎搭建场景)
决策树·设计模式·组合模式
hxj..12 小时前
【设计模式】外观模式
java·设计模式·外观模式
吾与谁归in13 小时前
【C#设计模式(10)——装饰器模式(Decorator Pattern)】
设计模式·c#·装饰器模式
无敌岩雀14 小时前
C++设计模式行为模式———命令模式
c++·设计模式·命令模式
马剑威(威哥爱编程)1 天前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
gjh12081 天前
单例模式和适配器模式的简单介绍
单例模式·适配器模式