文章目录
1. 定义
指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点
2. 适用场景
- 确保任何情况下都绝对只有一个实例
- ServletContext, ServletConfig, ApplicationContext, DBPool
3. 分类
- 饿汉式单例
- 懒汉式单例
- 注册式单例
- ThreadLocal单例
4. 饿汉式单例
在单例类首次加载时就创建实例
4.1 优/缺点
- 优点: 不会存在线程不安全问题
- 缺点: 浪费内存空间
4.2 饿汉式单例分类
- 直接通过new创建实例
- 通过static模块创建实例
4.2.1 直接通过new创建实例
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
}
4.2.2 通过static模块创建实例
public class HungryStaticSingleton {
private static final HungryStaticSingleton hungrySingleton;
private HungryStaticSingleton() {}
static {
hungrySingleton = new HungryStaticSingleton();
}
public static HungryStaticSingleton getInstance() {
return hungrySingleton;
}
}
5. 懒汉式单例
被外部调用时才创建实例
5.1 懒汉式单例分类
- 简单懒汉式单例
- 双重检查懒汉式单例
- 静态内部类懒汉式单例
5.1.1 简单懒汉式单例
- 在并发场景下存在线程安全问题
public class LazySimpleSingleton {
private static LazySimpleSingleton lazySimpleSingleton = null;
private LazySimpleSingleton(){}
public static LazySimpleSingleton getInstance() {
if (null == lazySimpleSingleton) {
lazySimpleSingleton = new LazySimpleSingleton();
}
return lazySimpleSingleton;
}
}
5.1.2 双重检查懒汉式单例
- 通过synchronized和双重检查, 解决
简单懒汉式单例
存在的线程安全问题
public class LazyDoubleCheckSingleton {
private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance() {
if (null == lazyDoubleCheckSingleton) {
synchronized (LazyDoubleCheckSingleton.class) {
if (null == lazyDoubleCheckSingleton) {
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
}
}
}
return lazyDoubleCheckSingleton;
}
}
5.1.3 静态内部类懒汉式单例
- 全程没有用到synchronized
- 巧妙利用了内部类的特性
- JVM底层执行逻辑,完美的避免了线程安全问题
- 存在被反射攻击的风险, 通过
if (null != LazyHolder.LAZY) {
解决反射问题
/**
* 静态内部类懒汉式单例
*/
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton(){
if (null != LazyHolder.LAZY) {
throw new RuntimeException("禁止反射创建实例");
}
}
// LazyHolder里面的逻辑需要等到外部方法调用时才执行
// 全程没有用到synchronized
// 巧妙利用了内部类的特性
// JVM底层执行逻辑,完美的避免了线程安全问题
public static LazyInnerClassSingleton getInstance() {
return LazyHolder.LAZY;
}
private static class LazyHolder {
private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
}
}
5.1.3 注册式单例
将每一个实例都缓存到统一的容器中,使用唯一标识获取实例