23种设计模式中的单例模式(Singleton Pattern)

249 阅读3分钟

单例模式介绍

单例模式是指一个类只允许创建一个实例,并提供一个全局访问点。它是一种常用的设计模式,通常用于管理共享资源、配置信息等。

单例模式的基本思想很简单:将类的构造函数定义为私有的,这样外部就无法通过构造函数来创建该类的实例;而通过一种特殊的方法来获取该类的唯一实例。这种特殊的方法通常被称为“getInstance”,它返回该类的唯一实例。由于该类的实例仅有一个,并且由该类自行创建,所以它可以保证全局唯一性,并且可以避免对资源的多重占用。

在实际应用中,单例模式有许多变体,例如懒汉式单例、饿汉式单例、双重检查锁单例、静态内部类单例等。下面我们来逐个介绍它们。

饿汉式单例模式

饿汉式单例模式是最简单的一种单例模式,它在类加载时就创建了实例,因此在程序运行期间不会再次创建实例,保证了全局唯一性。

public class Singleton { // 在类加载时就创建实例 private static Singleton instance = new Singleton();

// 将构造方法私有化,禁止外部通过构造方法创建实例
private Singleton() {}

// 提供一个公共的访问方法,用于获取该类的唯一实例
public static Singleton getInstance() {
    return instance;
}

}

懒汉式单例模式

懒汉式单例模式是在第一次使用时才进行实例化,可以节省内存空间。但是它需要考虑线程安全问题,否则可能出现多线程下创建多个实例的情况。

public class Singleton {
    // 用 volatile 关键字确保 instance 在多线程下的可见性
    private static volatile Singleton instance = null;
    
    // 将构造方法私有化,禁止外部通过构造方法创建实例
    private Singleton() {}
    
    // 提供一个公共的访问方法,用于获取该类的唯一实例
    public static Singleton getInstance() {
        if (instance == null) { // 如果 instance 为空,就进行实例化
            synchronized (Singleton.class) { // 保证多线程下只有一个线程进行实例化
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检查锁单例模式

双重检查锁单例模式是在懒汉式单例模式的基础上,加入了同步锁来保证线程安全,并且加入了第二次判断,避免多线程下创建多个实例。

public class Singleton {
    // 用 volatile 关键字确保 instance 在多线程下的可见性
    private static volatile Singleton instance = null;
    
    // 将构造方法私有化,禁止外部通过构造方法创建实例
    private Singleton() {}
    
    // 提供一个公共的访问方法,用于获取该类的唯一实例
    public static Singleton getInstance() {
        if (instance == null) { // 如果 instance 为空,就进行实例化
            synchronized (Singleton.class) { // 保证多线程下只有一个线程进行实例化
                if (instance == null) { // 第二次判断,避免多线程下创建多个实例
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

静态内部类单例模式

静态内部类单例模式是在类加载时会创建一个静态内部类,调用 getInstance 方法时才会去加载该内部类并初始化 INSTANCE 实例。该方式既保证了线程安全,也保证了懒加载和高效访问的特性。

public class Singleton {
    // 将构造方法私有化,禁止外部通过构造方法创建实例
    private Singleton() {}
    
    // 定义一个静态内部类,用于创建 Singleton 的唯一实例
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    // 提供一个公共的访问方法,用于获取该类的唯一实例
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

上面介绍的是四种常见的单例模式,每种单例模式都有其优缺点,根据实际需求进行选择。例如在单线程环境下,可以使用简单的饿汉式单例模式;而在多线程环境下,可以使用双重检查锁或静态内部类单例模式。