介绍
方式 | 特点 | 对比 |
---|---|---|
饿汉式 | 类加载阶段创建,多线程安全 | 简单快速 |
懒汉式-普通 | 延迟到运行创建单例,多线程安全,懒加载 | 直接方法加锁 |
懒汉式-DCL | 2次检查+1把锁,多线程安全,懒加载 | 检查之后再加锁,比普通懒汉式快 |
枚举 | 反序列化安全,多线程安全 | 反序列化安全 |
- 一般效率高使用饿汉式,有懒加载要求使用懒汉式,保证反序列化单例使用枚举式,有特殊要求使用DCL(Double Check Lock)
- 单例模式需要保证在“”多线程“”,“反序列化”情况下依旧单例
- 饿汉式类加载阶段创建单例,懒汉式运行阶段创建单例
- static变量可以保证多线程情况下依旧单例
- enum变量可以保证反序列化情况下依旧单例
应用
- spring IOC容器,向外提供单例对象
优点
- 内存中只有一个实例,减少了内存的开销,避免了对象频繁的被创建或销毁
代码
饿汉式
本代码实现特点:
- 多线程单例
- 饿汉式
- 性能高
补充知识
- static变量(无final修饰)在验证-准备阶段分配空间并默认初始化
<clinit>()
方法(类初始化方法)中执行static变量(无final修饰)的初始化<clinit>()
方法只在类的首次主动使用时被1个线程执行一次(是线程安全的)
hungry/SingletonXcrj
public class SingletonXcrj {
// 静态成员属性直接赋值,饿汉式,初始化阶段为singletonXcrj有且赋值1次,保证单例且饿汉
private static SingletonXcrj singletonXcrj = new SingletonXcrj();
// 私有化构造器并且不对外提供setter,getter,不允许new SingletonXcrj()
private SingletonXcrj() {
}
// 静态方法操作静态变量,直接返回属性中创建的单例对象
public static SingletonXcrj getSingleton() {
return SingletonXcrj.singletonXcrj;
}
}
hungry/Main
public class Main {
public static void main(String[] args) {
SingletonXcrj singletonXcrj = SingletonXcrj.getSingleton();
}
}
懒汉式-普通
本代码特点
- 多线程单例
- 懒汉式
- 性能比DCL低
lazy/SingletonXcrj
public class SingletonXcrj {
// 静态成员属性,未赋值
private static SingletonXcrj singletonXcrj;
// 私有化构造器并且不对外提供setter,getter,不允许new SingletonXcrj()
private SingletonXcrj() {
}
// 静态方法操作静态变量,synchronized 保证多线程单例
public static synchronized SingletonXcrj getSingleton() {
return SingletonXcrj.singletonXcrj = new SingletonXcrj();
}
}
lazy/Main
public class Main {
public static void main(String[] args) {
SingletonXcrj singletonXcrj = SingletonXcrj.getSingleton();
}
}
懒汉式DCL-Double Check Lock
介绍
- 为了提高普通懒汉式的速度
本代码特点
- 双重检查+1把所
- 多线程单例
dcl/SingletonXcrj
public class SingletonXcrj {
// 静态成员属性,未赋值
// volatile关键字保证 变量的可见性和有序性
private volatile static SingletonXcrj singletonXcrj;
// 私有化构造器并且不对外提供setter,getter,不允许new SingletonXcrj()
private SingletonXcrj() {
}
// 静态方法操作静态属性
public static SingletonXcrj getSingleton() {
// 第1重检查
if (SingletonXcrj.singletonXcrj == null) {
// 加锁,再检查
synchronized (SingletonXcrj.class) {
// 第2重检查
if (SingletonXcrj.singletonXcrj == null) {
return SingletonXcrj.singletonXcrj = new SingletonXcrj();
}
}
}
return SingletonXcrj.singletonXcrj;
}
}
dcl/Main
public class Main {
public static void main(String[] args) {
SingletonXcrj singletonXcrj = SingletonXcrj.getSingleton();
}
}
枚举式
介绍
- 反序列化单例
- 多线程单例
- 枚举式过程:类的主动使用,导致类加载阶段执行()方法调用私有化的构造方法初始化SINGLETON静态变量
补充知识 - 枚举量默认public static final
- 枚举构造函数默认private
- 反序列化安全,编译器不允许任何对枚举序列化机制的定制操作
enums/SingletonHolder
/*
* 过程:
* 类的主动使用,导致类加载阶段执行<clinit>()方法调用私有化的构造方法初始化SINGLETON静态变量
* */
public enum SingletonHolder {
// 枚举量默认public static final
SINGLETON;
private SingletonResource singletonResource;
// 枚举构造函数默认private
SingletonHolder() {
this.singletonResource = new SingletonResource();
System.out.println("1234");
}
// 未要求静态方法
public SingletonResource getSingletonResource() {
return SINGLETON.singletonResource;
}
}
enums/SingletonResource
public class SingletonResource {
public void SayHi(){
System.out.println("hi, I am singleton!");
}
}
enums/Main
public class Main {
public static void main(String[] args) {
SingletonResource singletonResource=SingletonHolder.SINGLETON.getSingletonResource();
}
}