并发场景保证线程安全单例模式研究
/**
* 懒汉模式
* 单例实例在第一次使用时进行创建
*/
@NotThreadSafe
public class SingletonExample1 {
// 私有构造函数
private SingletonExample1() {
}
// 单例对象
private static SingletonExample1 instance = null;
// 静态的工厂方法
public static SingletonExample1 getInstance() {
if (instance == null) {
instance = new SingletonExample1();
}
return instance;
}
}
/**
* 饿汉模式
* 单例实例在类装载时进行创建
*/
@ThreadSafe
public class SingletonExample2 {
// 私有构造函数
private SingletonExample2() {
}
// 单例对象
private static SingletonExample2 instance = new SingletonExample2();
// 静态的工厂方法
public static SingletonExample2 getInstance() {
return instance;
}
}
/**
* 懒汉模式
* 单例实例在第一次使用时进行创建
*/
@ThreadSafe
@NotRecommend
public class SingletonExample3 {
// 私有构造函数
private SingletonExample3() {
}
// 单例对象
private static SingletonExample3 instance = null;
// 静态的工厂方法
public static synchronized SingletonExample3 getInstance() {
if (instance == null) {
instance = new SingletonExample3();
}
return instance;
}
}
/**
* 懒汉模式 -》 双重同步锁单例模式
* 单例实例在第一次使用时进行创建
*/
@NotThreadSafe
public class SingletonExample4 {
// 私有构造函数
private SingletonExample4() {
}
// 1、memory = allocate() 分配对象的内存空间
// 2、ctorInstance() 初始化对象
// 3、instance = memory 设置instance指向刚分配的内存
// JVM和cpu优化,发生了指令重排
// 1、memory = allocate() 分配对象的内存空间
// 3、instance = memory 设置instance指向刚分配的内存
// 2、ctorInstance() 初始化对象
// 单例对象
private static SingletonExample4 instance = null;
// 静态的工厂方法
public static SingletonExample4 getInstance() {
if (instance == null) { // 双重检测机制 // B
synchronized (SingletonExample4.class) { // 同步锁
if (instance == null) {
instance = new SingletonExample4(); // A - 3
}
}
}
return instance;
}
}
/**
* 懒汉模式 -》 双重同步锁单例模式
* 单例实例在第一次使用时进行创建
*/
@ThreadSafe
public class SingletonExample5 {
// 私有构造函数
private SingletonExample5() {
}
// 1、memory = allocate() 分配对象的内存空间
// 2、ctorInstance() 初始化对象
// 3、instance = memory 设置instance指向刚分配的内存
// 单例对象 volatile + 双重检测机制 -> 禁止指令重排
private volatile static SingletonExample5 instance = null;
// 静态的工厂方法
public static SingletonExample5 getInstance() {
if (instance == null) { // 双重检测机制 // B
synchronized (SingletonExample5.class) { // 同步锁
if (instance == null) {
instance = new SingletonExample5(); // A - 3
}
}
}
return instance;
}
}
volatile怎样做到防止类初始化时jvm重排序?
当有volatile时,就会限制这里的重排序,这是jmm里约定的,并由jdk来保证的,本质上是volatile修饰的变量对应的读写操作在生成cpu指令时不允许编译器进行重排序,这是和其他变量的区别,除了限制重排序之外,还会额外插入内存屏障,来保证可见性。

双重检测机制,线程不安全。因为指令重排序,有可能会线程A的instance已经指向了分配的内存。但还没有初始化对象。这是线程B在执行if(instance==null)时,返回false,直接返回了instance,但instance并没有初始化对象。
/**
* 饿汉模式
* 单例实例在类装载时进行创建
*/
@ThreadSafe
public class SingletonExample6 {
// 私有构造函数
private SingletonExample6() {
}
// 单例对象
private static SingletonExample6 instance = null;
static {
instance = new SingletonExample6();
}
// 静态的工厂方法
public static SingletonExample6 getInstance() {
return instance;
}
public static void main(String[] args) {
System.out.println(getInstance().hashCode());
System.out.println(getInstance().hashCode());
}
}
/**
* 枚举模式:最安全
*/
@ThreadSafe
@Recommend
public class SingletonExample7 {
// 私有构造函数
private SingletonExample7() {
}
public static SingletonExample7 getInstance() {
return Singleton.INSTANCE.getInstance();
}
private enum Singleton {
INSTANCE;
private SingletonExample7 singleton;
// JVM保证这个方法绝对只调用一次
Singleton() {
singleton = new SingletonExample7();
}
public SingletonExample7 getInstance() {
return singleton;
}
}
}
@ThreadSafe
public class AtomicSingleton {
private AtomicSingleton() {}
private static AtomicReference<AtomicSingleton> instance = new AtomicReference<>();
public static AtomicSingleton getInstance() {
if (instance.get() == null) {
instance.compareAndSet(null, new AtomicSingleton());
}
return instance.get();
}
public static void main(String[] args) {
SingletonExample7 instance = SingletonExample7.getInstance();
SingletonExample7 instance2 = SingletonExample7.getInstance();
System.out.println("instance = " + instance);
System.out.println("instance2 = " + instance2);
}
}