定义

单例模式(Singleton Pattern)是一种创建型设计模式,它保证一个类只有一个实例,并提供一个公开节点以实现对唯一实例的访问。

使用场景

该模式主要解决一个全局类频繁使用导致的创建与销毁,应用该模式可以有效的控制实例数目,节省系统资源开销。

优点

  1. 在内存里只存在一个实例,减小了内存的开销(尤其是在需要频繁创建与销毁的场景下)
  2. 避免对资源的多重占用(例如执行IO操作时相关系统资源的占用)

缺点

没有接口,不能继承。与单一职责原则冲突:一个类应该只关心内部逻辑,而不关心外部如何进行实例化。

实现

懒汉式

懒加载:是

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private static Singleton instance;
private Singleton() {} //私有构造方法,防止外部访问
public static synchronized Singleton getInstance() { // 提供外部访问节点
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

优点: 第一次调用才进行初始化,避免内存浪费

缺点:必须加锁(synchronized)才能保证单例,但加锁会影响执行效率。

饿汉式

懒加载:否

1
2
3
4
5
6
7
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}

优点:没有加锁,执行效率相对较高。

缺点:类加载时就初始化,可能造成一定的内存浪费

双重校验锁(DCL)

懒加载:是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

该实现采用双锁机制,在确保多线程安全的情况下也能提供高性能,但实现逻辑相较其他方法略显复杂。

登记式/静态内部类

懒加载:是

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}

private Singleton() {}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

优点:这种实现方式能达到双重校验锁一样的功效,但实现更为简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。

缺点:这种方式只适用于静态域的情况,双重校验锁的方式可以在实例域需要延迟初始化时使用。