单例模式有哪些常见的实现方式?
单例模式有多种实现方式,每种方式都有其特点和应用场景。以下是常见的几种实现方式:
- 懒汉式(Lazy Initialization):
- 这种方式支持延迟加载,即单例实例在被客户端首次请求时才创建。
- 不支持多线程,因为没有加锁操作,所以在多线程环境下不能保证单例的唯一性。
- 线程安全的懒汉式:
- 这种方式在懒汉式的基础上增加了同步锁
synchronized
,使其在多线程中保持单例。 - 但每次访问
getInstance()
方法时都要进行线程锁定判断,在高并发环境下会导致系统性能下降。
- 这种方式在懒汉式的基础上增加了同步锁
- 饿汉式(Eager Initialization):
- 在类加载时就创建实例,基于类加载机制,避免了多线程的同步问题。
- 如果单例类的构造方法中没有包含过多的操作处理,饿汉式其实可以接受。
- 双重校验锁(Double-Checked Locking):
- 这种方式在懒汉式的基础上进行了改进,只有在实例未被创建时才进行同步,这样可以减少大部分的同步开销。
- 实现复杂,需要特别注意
instance
需要被声明为volatile
,否则可能因为JVM的指令重排导致使用到未完全初始化的实例。
- 静态内部类(Static Inner Class):
- 利用类的加载机制来保证初始化实例时只有一个线程。
- 静态内部类方式在
Singleton
类被加载时并不需要立即实例化,而是在需要实例化时,调用getInstance()
方法,才会加载StaticHolder
类,从而完成Singleton
的实例化。 - 类的静态属性只会在第一次加载类的时候初始化,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
- 枚举(Enum):
- 这是实现单例的最简洁方法,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
- 可以通过
EasySingleton.INSTANCE.doSomething()
的方式调用单例实例的方法。
以下是静态内部类实现单例模式的一个例子:
public class Singleton {
// 私有构造函数
private Singleton() {}
// 静态内部类
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
// 全局访问点
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
public void doSomething() {
// 实例方法...
}
}
public class Main {
public static void main(String[] args) {
// 通过Singleton类的getInstance方法获取唯一实例
Singleton singleton = Singleton.getInstance();
singleton.doSomething();
}
}
以上就是单例模式的主要实现方式,实际应用时应根据具体情况选择合适的实现方法。