一、单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。
单例模式中:
- 这个类只能有一个实例
- 这个类必须自己创建自己的唯一实例
- 这个类必须向外提供访问其唯一实例的方式
二、Java中单例模式的实现方式
Java中常见的单例模式实现方式有五种:
1.饿汉式(Eager Initialization)
饿汉式在类加载时就创建单例对象,所以在调用时不需要再创建对象,直接使用即可。这种实现方式比较简单,但在某些情况下可能会造成资源的浪费。
public class SingletonEager {
private static final SingletonEager INSTANCE = new SingletonEager();
private SingletonEager() {}
public static SingletonEager getInstance() {
return INSTANCE;
}
}
2.懒汉式(Lazy Initialization)
懒汉式在调用时才创建单例对象,这种实现方式避免了资源浪费,但会有线程安全问题。
public class SingletonLazyUnsafe {
private static SingletonLazyUnsafe instance;
private SingletonLazyUnsafe() {}
public static SingletonLazyUnsafe getInstance() {
if (instance == null) {
instance = new SingletonLazyUnsafe();
}
return instance;
}
}
// 注意:懒汉式在多线程环境下是不安全的
3.双重检查锁定(Double-Check Locking)
双重检查锁定是在懒汉式的基础上加入了双重检查锁机制,可以保证线程安全。
public class SingletonDoubleCheck {
private volatile static SingletonDoubleCheck instance;
private SingletonDoubleCheck() {}
//双重检查和加锁来保证线程安全
public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null) {
instance = new SingletonDoubleCheck();
}
}
}
return instance;
}
}
4.静态内部类(Static Inner Class)
静态内部类这个方式是将单例对象作为静态内部类的一个静态变量,这种实现方式既可以保证线程安全,又可以实现懒加载。其实现原理是:外部类加载时,并不会立刻加载内部类,内部类不被加载,就不会去创建实例,只有当getInstance
方法被调用时,才会加载内部类去创建实例(而且类加载的过程,在JVM中是被设计成线程安全的),所以既保证线程安全又实现了懒加载。
public class SingletonStaticInner {
private SingletonStaticInner() {}
private static class SingletonHolder {
private static final SingletonStaticInner INSTANCE = new SingletonStaticInner();
}
public static SingletonStaticInner getInstance() {
return SingletonHolder.INSTANCE;
}
}
5.枚举(Enumeration)
枚举是实现单例模式的最佳方式,将单例对象定义为一个枚举类型,这种实现方式可以保证线程安全,同时也可以防止反射、反序列化破坏单例模式。
public enum SingletonEnum {
INSTANCE;
// 定义方法或属性
public void someMethod() {
// ...
}
}
// 使用
SingletonEnum.INSTANCE.someMethod();
注意:除了枚举方式,前面四种方式实现的单例模式都存在反射和反序列化破坏单例的问题
(在不做额外处理的情况下,通过反射可以突破构造方法的私有化限制,强行创建新的实例。而在反序列化时,可能会生成新的对象实例,而不是保持原有的单例状态。)