美文网首页
通过双重校验单例模式理解Volatile关键字

通过双重校验单例模式理解Volatile关键字

作者: 麟2019 | 来源:发表于2019-06-19 17:42 被阅读0次

双重校验单例模式实现:

public class Singleton {
    public static volatile Singleton instance = null;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (instance == null) { // 拒绝掉当对象不为空的时候剩余的线程
            synchronized (instance) {
                if (instance == null) { // 处理 同时进来两个线程的情况
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

以上代码看起来不需要volatile修饰instance就可以保证线程安全,但是考虑重排序和可见性问题后,没有volatile是不能保证线程安全的。

public class Singleton {
    private static Singleton uniqueInstance;

    private Singleton(){
    }

    public static Singleton getInstance(){
        if(uniqueInstance == null){ //#1
            synchronized(Singleton.class){ //#2
                if(uniqueInstance == null){ //#3
                    uniqueInstance = new Singleton(); //#4
                    System.out.println(Thread.currentThread().getName() + ": uniqueInstance is initalized..."); //#5.1
                } else {
                    System.out.println(Thread.currentThread().getName() + ": uniqueInstance is not null now..."); //#5.2
                }
            }
        }
        return uniqueInstance;
    }
}

问题一:创建多个实例(缓存导致的问题)

  1. thread2进入#1, 这时子线程的uniqueInstance都是为空的,thread2让出CPU资源给thread3
  2. thread3进入#1, 这时子线程的uniqueInstance都是为空的, thread3让出CPO资源给thread2
  3. thread2会依次执行#2,#3,#4, #5.1,最终在thread2里面实例化了uniqueInstance。thread2执行完毕让出CPO资源给thread3
  4. thread3接着#1跑下去,跑到#3的时候,由于#1里面拿到的uniqueInstance还是空(并没有及时从thread2里面拿到最新的),所以thread3仍然会执行#4,#5.1
  5. 最后在thread2和thread3都实例化了uniqueInstance

问题二:空指针(重排序导致的问题)

对象实例化的步骤:

  1. 分配内存空间。
  2. 初始化对象。
  3. 将内存空间的地址赋值给对应的引用。

实际中2和3可能会调换执行顺序


image.png

volatile能够有效的防止指令重排,实现的原理是内存屏障
内存屏障的功能:
它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
它会强制将对缓存的修改操作立即写入主存;
如果是写操作,它会导致其他CPU中对应的缓存行无效。

相关文章

网友评论

      本文标题:通过双重校验单例模式理解Volatile关键字

      本文链接:https://www.haomeiwen.com/subject/pbxlqctx.html