读书笔记 仅供参考
Singleton 模式
Singleton 模式是为了满足“只能创建一个实例”的需求。
- 想确保任何情况下都绝对只有一个实例
- 想在程序上表现出“只存在一个实例”
UML
代码
Singleton 类,单例类
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {
System.out.println("生成一个实例。");
}
public static Singleton getInstance() {
return singleton;
}
}
Main 类测试
public class Main {
public static void main(String[] args) {
System.out.println("Start.");
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
if(obj1 == obj2) {
System.out.println("obj1 与 obj2 是相同的实例。");
} else {
System.out.println("obj1 与 obj2 是不同的实例。");
}
System.out.println("End.");
}
}
相关的设计模式
下面的模式大多数情况下只会生成一个实例
- AbstractFactory
- Bulider
- Facade
- Prototype
扩展(懒汉,饿汉,枚举,登记)
一般生成单例,有四种方式会使用比较多,就是懒汉,饿汉,枚举和登记。
懒汉
懒汉式生成单例属于延迟加载,在需要使用到的时候再加载,会有出现线程安全的风险。
public class Singleton {
private Singleton() {}
private static Singleton single=null;
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
为了避免出现线程的问题,有几种方法可以实现
- 同步
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
- 双重检测
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
- 静态内部类(比上面两种好)
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
饿汉式
饿汉式就是在类加载时就把实例尊卑好,上文采用的方法就是饿汉式,不会出现线程的问题。
枚举
上面两种方法都使用了私有的构造方法,但是通过反射是可以再次调用私有的方法,产生新的实例,并且在序列化时也会出现问题。
枚举就可以避免上述的问题。
public enum Elvis {
INSTANCE;
}
登记式
登记式没有怎么见过或用过,是维护一组实例,类似 KV 结构,可以通过类名将实例取出,内部应该是采用饿汉式。