单例模式 是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。它属于Gang of Four设计模式之一,常用于需要控制资源访问或者管理共享资源的场景,如数据库连接、日志记录、应用配置等。
单例模式的实现通常涉及以下几个关键步骤:
将类的构造函数设为私有,阻止外部通过new操作符创建类的实例。
在类内部创建一个该类的静态私有实例。
提供一个公共的静态方法,用于获取这个类的唯一实例。
实现方式
单例模式有几种不同的实现方式,每种方式都有其适用的场合:
懒汉式(Lazy Initialization) - 实例在首次使用时创建。
饿汉式(Eager Initialization) - 实例在类被加载时创建。
双重检查锁定(Double-Checked Locking) - 结合了懒汉式和同步锁的优点,实现了线程安全同时又确保了性能。
静态内部类(Static Inner Class) - 利用Java语言特性,实现了懒加载和线程安全的单例。
枚举(Enum) - 利用枚举的特性,实现单例,并自动支持序列化机制防止多次实例化。
示例代码
以下是懒汉式的一个简单实现:
public class Singleton {
private static Singleton instance;
private Singleton() { }
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种实现方式是线程安全的,但是每次调用getInstance()时都会进行同步,这会导致不必要的同步开销。在多线程情况下,这个开销可能会显著影响性能。
为了提高性能,我们可以使用双重检查锁定:
public class Singleton {
private static volatile Singleton instance;
private Singleton() { }
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
双重检查锁定先测试实例是否已经创建,如果尚未创建,才进行同步。这种方式绝大多数情况下不需要同步。
另一种实现模式是使用静态内部类:
public class Singleton {
private Singleton() { }
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这个模式利用了类加载机制来保证初始化实例时只有一个线程。SingletonHolder 是一个静态内部类,它包含一个静态属性INSTANCE,当SingletonHolder类被加载到内存时会初始化INSTANCE对象,而且由于是静态的,这个过程只会执行一次。
最后,枚举的实现方式是最简单的,而且无偿提供了序列化机制,并由JVM从根本上提供保障,不会通过反射攻击重新创建新的实例。
public enum Singleton {
INSTANCE;
public void doSomething() {
// Perform operation here
}
}
在这个枚举类的实现中,INSTANCE 是一个枚举元素,它被构造成Singleton的一个实例。使用枚举来实现单例模式是无法通过反射创建枚举对象的,而且它更简洁,并且自动支持序列化机制,防止多次实例化。
每种实现方法都有各自的适应场景,考虑因素包括性能需求、资源管理以及平台和语言特性。在实际应用中,应当根据具体情况选择合适的单例实现方式。