设计模式学习-单例模式
大约 2 分钟
什么是单例模式
- 一个类只有一个实例。即使用单例模式的类的构造方法必须是
private
,且类中含有一个当前类的静态成员变量。 - 自行实例化,并向整个系统提供这个实例。即使用单例模式的类的初始化必须在类的内部,且要对外提供一个公开的方法来提供该类的实例对象。
单例模式的多种实现方式
单例模式的实现方式有很多种,比较常见的:
饿汉式(类加载时进行实例化)
懒汉式(在第一次使用时再实例化)
利用枚举类实现
饿汉式的代码实现:
public class Singleton_01 {
public static Singleton_01 INSTANCE = new Singleton_01();
private Singleton_01() {}
public static Singleton_01 getInstance() {
return INSTANCE;
}
}
懒汉式的代码实现:
使用懒汉式进行实现,为确保线程安全,需要使用synchronized
上锁,确保使用单例模式的类仅会被实例化一次,这里会使用到双重检查锁,即不是给对外提供实例的方法上锁,而是在方法内部,主要目的是减少锁的粒度。在使用双重检查锁的时候,当前类的静态成员变量必须使用volatile
进行修饰,避免因为指令重排序导致的线程安全问题。
public class Singleton_02 {
private static volatile Singleton_02 INSTANCE;
private Singleton_02() {}
public static Singleton_02 getInstance() {
if (INSTANCE == null) {
synchronized (Singleton_02.class) {
if (INSTANCE == null) INSTANCE = new Singleton_02();
}
}
return INSTANCE;
}
}
利用枚举类的代码实现:
使用枚举类进行实现,主要借助于枚举类的特性,成员会使用static
与final
进行修饰,且构造方法私有化。和饿汉式有些相似,但代码量非常简洁。
public enum Singleton_03 {
INSTANCE;
}
单例模式存在的问题
单例模式对于每个类一定只有一个实例吗?
不一定。
在分布式环境下,会有多个 JVM,每个 JVM 都有一个实例。
或是同一个 JVM 使用多个类加载器,同时加载了这个类。
单例模式不适用于有状态。
如果一个使用单例模式的类是有状态的,比如该类有个成员变量的值是 10,在某个地方用的时候,将其修改为了 20,但有可能在其他地方又被修改为了 30。
所以,一般使用单例模式的类都是无状态的,例如工具类。