定义
单例模式
确保一个类在整个系统中只有一个实例,并提供一个全局访问点来访问该实例。
实现方式
懒汉式(线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}优点:实现了懒加载,只在需要时才实例化instance,节省了资源。
缺点:线程不安全,在多线程环境下,如果有多个线程同时进入if (instance == null),同时instance为null,就可能有多个线程执行instance = new Singleton();,从而导致多次实例化。
懒汉式(线程安全)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}优点:通过给getInstance加锁实现了线程安全。
缺点:在instance实例化后锁依然存在,只有拿到锁的线程才能进入该方法,性能上有损耗。
饿汉式(线程安全)
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){
}
public static Singleton getInstance() {
return instance;
}
}优点:提前实例化instance,避免了线程不安全的问题。
缺点:没有实现懒加载,如果该实例并没有被使用就会造成资源浪费。
双重检查锁(线程安全)
public class Singleton {
// volatile 禁止指令重排,防止instance指向未初始化完成的实例
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
// 第二个if:防止多个线程进入第一个if从而导致instance被多次实例化
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}优点:实现懒加载的同时也实现了线程安全。
volatile关键字的作用:
instance = new Singleton(); 这行代码在 JVM 层面分为三步执行:
- 分配内存空间。
- 初始化对象(执行构造函数)。
- 将
instance指向分配的内存地址。
但是因为 JVM 的指令重排,执行顺序可能变成了1 -> 3 -> 2。如果执行了3却还没有执行2,此时正好有其他线程访问该方法,就会拿到一个未初始化完成的实例。
静态内部类(线程安全)
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}优点:实现懒加载的同时也实现了线程安全。
懒加载:当外部类 Singleton 被加载时,内部类 SingletonHolder 并不会被立即加载。当第一次调用getInstance() 方法时,JVM 才会去加载 SingletonHolder 并初始化INSTANCE。
线程安全:JVM保证了只会实例化一次。
枚举
public enum Singleton {
INSTANCE;
// 业务方法
public void doSomething() {
}
}优点:实现简单,线程安全,防止反射攻击。
缺点:没有实现懒加载。