你好!今天,我们将从 Java 单例模式开始,深入探讨各种设计模式的细节。让我们回顾一下:我们对设计模式一般了解多少?设计模式是我们可以用来解决许多已知问题的最佳实践。设计模式通常不依赖于任何编程语言。将它们视为一组建议,以帮助您避免错误并避免重新发明轮子。
Java中的单例是什么?
单例模式是最简单的类级设计模式之一。有时人们说“这个类是单例的”,这意味着该类实现了单例设计模式。有时需要编写一个类,我们将实例化限制为单个对象。例如,一个类负责记录或连接到一个数据库。单例设计模式描述了我们如何实现这一点。单例是一种做两件事的设计模式:-
它保证永远只有一个类的实例。
-
它提供对该实例的单点全局访问。
-
私有构造函数。这限制了在类本身之外创建类对象的能力。
-
返回类实例的公共静态方法。此方法称为getInstance。这是对类实例的全局访问点。
实施方案
单例设计模式以各种方式应用。每个选项都以其自己的方式是好的和坏的。一如既往,这里没有完美的选择,但我们应该争取一个。首先,让我们决定好与坏的构成,以及影响我们如何评估设计模式的各种实现的指标。让我们从好的开始。以下是使实施更具吸引力和吸引力的因素:-
惰性初始化:直到需要时才创建实例。
-
简单透明的代码:这个指标当然是主观的,但它很重要。
-
线程安全:在多线程环境下正确运行。
-
多线程环境中的高性能:共享资源时很少或没有线程阻塞。
-
没有惰性初始化:当应用程序启动时加载类,无论是否需要它(矛盾的是,在 IT 世界中,惰性更好)
-
复杂且难以阅读的代码。这个指标也是主观的。如果您的眼睛开始流血,我们会假设实施不是最好的。
-
缺乏线程安全。换句话说,“线程危险”。多线程环境下的错误操作。
-
多线程环境下的性能不佳:线程在共享资源时一直或经常相互阻塞。
代码
现在我们准备好考虑各种实施方案并指出优缺点:简单的
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
最简单的实现。优点:
-
简单透明的代码
-
线程安全
-
多线程环境下的高性能
- 没有惰性初始化。
延迟初始化
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
优点:
-
延迟初始化。
-
不是线程安全的
同步访问
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
优点:
-
延迟初始化。
-
线程安全
-
多线程性能差
双重检查锁定
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
优点:
-
延迟初始化。
-
线程安全
-
多线程环境下的高性能
-
Java 1.5 以下的早期版本不支持(从 1.5 版本开始固定使用 volatile 关键字)
班级持有人
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
优点:
-
延迟初始化。
-
线程安全。
-
多线程环境下的高性能。
-
正确的操作需要保证单例对象的初始化没有错误。否则,对getInstance方法的第一次调用将导致ExceptionInInitializerError,所有后续调用将产生NoClassDefFoundError。
单例模式的优缺点
通常,单身人士会完全按照预期进行操作:-
它保证永远只有一个类的实例。
-
它提供对该实例的单点全局访问。
-
单例违反了单一职责原则:单例类除了直接的职责外,还控制着实例的数量。
-
普通类对单例的依赖在类的公共契约中是不可见的。
-
全局变量不好。最终,单例会变成一个庞大的全局变量。
-
单例的存在降低了整个应用程序的可测试性,尤其是使用单例的类。
GO TO FULL VERSION