设计模式 - 单例模式

140 阅读2分钟

本文已参加【新人创作礼】活动,一起开启掘金创作之路。

单例模式(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.

[2] Java-利用反射访问类的私有(private)属性及方法&private的意义