本文已参加【新人创作礼】活动,一起开启掘金创作之路。
单例模式(Singleton Pattern)
-
定义 确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例[^1]。
-
饿汉式:
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
- 懒汉式:
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
- 双重检查:
public class Singleton {
private static final volatile Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (INSTANCE) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
- 静态内部类 这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。 优点:避免了线程不安全,延迟加载,效率高。
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
饿汉式、双重检查和静态内部类中单例对象都使用final修饰符,是必须的吗? 答案:是的。不加final的话可以被反射获取或修改,是不安全的[^2]。
参考文献
[1] 刘伟. 设计模式的艺术[M]. 清华大学出版社, 2020.