1. 饿汉式
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
2. 懒汉式
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public synchronized Singleton getInstance() {
if (null == instance) {
instance = new Singleton();
}
return instance;
}
}
3. 双重检测
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) { // 此处为类级别的锁
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
双重检查锁疑问: https://blog.csdn.net/xiakepan/article/details/52444565
问:我的疑问是有synchronize同步,就算java有指令重排序,也应该是线程1按132顺序全部执行完线程2才能拿到锁吧.
答: 现在关键点不是拿到锁的问题。而是在第一重非空判断。 如果指令重排,线程A先将没初始化完成的实例刷新回主存,那么线程B在第一重非空判断时候就直接返回了不完整对象,与锁没关系。
昨晚查了下,其实在释放锁时,只是保证必须要把变量写回主存,但不代表只有在释放锁时才会写,之前也可能会更新变量就写回主存,所以这里确实是必须要加volatile的,不然确实可能会拿到未促使化完成的对象,引发空指针异常
https://www.cnblogs.com/xz816111/p/8470048.html
为了解决上述问题,需要在uniqueSingleton
前加入关键字volatile
。使用了volatile关键字后,重排序被禁止,所有的写(write)操作都将发生在读(read)操作之前。
至此,双重检查锁就可以完美工作了。