饿汉式(饥饿加载)
- static在类加载时初始化一次,保证线程安全,final保证变量不可更改
- 如果构造函数涉及I/O等耗时较长的操作会增加类加载时间
- 过早加载也会浪费内存
- 无法防止反射攻击
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
try {
//do somethings...
Thread.sleep(3*1000);
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
}
public static Singleton getInstance() {
return instance;
}
}
饿汉式
枚举本身保证线程安全,通过javap命令反编译可以发现枚举最终被编译成了一个继承java.lang.Enum的不可变(final)类。当类被加载时,INSTANCE 被定义为 static final 在 static 方法块中被实例化,属于饿汉式加载。
@see: Java枚举实现原理
public enum EnumSingleton {
INSTANCE;
EnumSingleton() {
//防止反射调用
synchronized (EnumSingleton.class) {
if (null != valueOf("INSTANCE")) {
throw new RuntimeException("Instance is already exists.");
}
}
}
}
懒汉式
简单判断实例是否存在:1 - 存在立即返回,2 - 不存在先创建再返回
- 线程不安全
public class SimpleLazySingleton {
private static SimpleLazySingleton instance;
private SimpleLazySingleton() {
//防止反射攻击
synchronized (SimpleLazySingleton.class) {
if (null != instance) {
throw new RuntimeException("Instance is already exists.");
}
}
}
public static SimpleLazySingleton getInstance() {
if (instance == null) {
instance = new SimpleLazySingleton();
}
return instance;
}
}
懒汉式
方法加锁
- 线程安全
- 方法同步导致每次调用都加锁,影响性能,实际上我们只需要在实例初始化的时候加锁
public class SyncLazySingleton {
//加上volatile修饰防止指令重排
private static volatile SyncLazySingleton instance;
private SyncLazySingleton() {
//防止反射攻击
synchronized (SyncLazySingleton.class) {
if (null != instance) {
throw new RuntimeException("Instance is already exists.");
}
}
}
public static synchronized SyncLazySingleton getInstance() {
if (instance == null) {
instance = new SyncLazySingleton();
}
return instance;
}
}
懒加载
方法块加锁,细化了锁的粒度
对象创建过程:
- 先在堆中开辟一块空间
- 给开辟的空间分配一个地址
- 把所有非静态成员变量加载到开辟的空间中
- 对所有非静态成员变量默认值初始化
- 构造函数入栈,调用构造函数,如果包含基类,则基类先执行1-5步
- 将堆中分配的地址赋值给变量
JVM指令重排:无法保证构造函数创建对象和将堆中分配的地址赋值给变量的顺序性
如果线程A到达同步块,A在将堆中分配的地址赋值给变量后直接退出方法块,
此时构造方法并未执行,B进入方法直接返回实例的引用将会得到一个不完全构造的单例对象
- 无法阻止指令重排
- 无法阻止反射
public class DoubleCheckLazySingleton {
private static DoubleCheckLazySingleton instance;
private DoubleCheckLazySingleton() {
try {
//do somethings...
Thread.sleep(3*1000);
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
}
public static DoubleCheckLazySingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckLazySingleton.class) {
if (instance == null) {
instance = new DoubleCheckLazySingleton();
}
}
}
return instance;
}
}
懒加载
双重检查锁定,通过增加局部变量和增加同步锁定解决指令重排
- 线程安全
public class DoubleCheckLazySingleton {
private static DoubleCheckLazySingleton instance;
private DoubleCheckLazySingleton() {
//防止反射攻击
synchronized (DoubleCheckLazySingleton.class) {
if (null != instance) {
throw new RuntimeException("Instance is already exists.");
}
}
}
public static DoubleCheckLazySingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckLazySingleton.class) {
DoubleCheckLazySingleton temp = instance;
if (temp == null) {
synchronized (DoubleCheckLazySingleton.class) {
temp = new DoubleCheckLazySingleton();
}
instance = temp;
}
}
}
return instance;
}
}
懒加载
双重检查锁定,通过volatile关键字阻止编译时和运行时的指令重排
- 线程安全
public class DoubleCheckLazySingleton {
private static volatile DoubleCheckLazySingleton instance;
private DoubleCheckLazySingleton() {
//防止反射攻击
synchronized (DoubleCheckLazySingleton.class) {
if (null != instance) {
throw new RuntimeException("Instance is already exists.");
}
}
}
public static DoubleCheckLazySingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckLazySingleton.class) {
if (instance == null) {
instance = new DoubleCheckLazySingleton();
}
}
}
return instance;
}
}
懒加载
静态内部类,通过静态内部类的方式保证线程安全和延迟加载(仅在SingletonHolder被加载时才会实例化INSTANCE)
- 线程安全
*/
public class Singleton {
private Singleton() {
//防止反射调用
synchronized (SingletonHolder.class) {
if (null != SingletonHolder.INSTANCE) {
throw new RuntimeException("Instance is already exists.");
}
}
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
}