关于volatile禁止指令重排序的理解 ------以单例模式为例

单例模式,是设计模式的一种。具体实现细节为,某一个类,只对外提供同一个对象的实例。
特点:1.私有的构造方法(外界无法new出对象)
2.开放一个方法,返回类型为该单例对象
实现方式: 1.饿汉模式:new对象操作在类加载的时候就执行。也就是说, 即使我没有要获取这个对象,这个对象也已经被new出来了。

public class Singleton {
    //饿汉模式
    private static Singleton instance = new Singleton();
    private Singleton(){}
    public Singleton getInstance(){
        return instance;
    }
}

优点:线程安全。
缺点:占用不必要的空间(有时候不急着使用,但已经被new出来了),并且,如果在类加载的时候抛出异常,那么new出来的这个对象永久性损坏,不能再使用了。
2.懒汉模式

  private static Singleton instance =null;
    private Singleton(){}
    public Singleton getInstance(){
       if(instance==null){
           instance = new Singleton();
       }
       return instance;
    }

类加载时不初始化对象,在需要得到该对象时才初始化。该模式线程不安全
3.懒汉式+线程安全

  private static Singleton instance =null;
    private Singleton(){}
    public synchronized Singleton getInstance(){
       if(instance==null){
           instance = new Singleton();
       }
       return instance;
    }

缺点:即使已经初始化完毕,依旧不能并发并行执行,因为有锁的存在,效率比较低
4.双重校验锁

  private static volatile Singleton instance =null;
    private Singleton(){}
    public Singleton getInstance(){
       if(instance==null){
           synchronized (Singleton.class){
               if(instance==null){
                   instance = new Singleton();
               }
           }
       }
       return instance;
    }

完美的解决了上述问题。加上volatile的目的是保证第一个if读的线程安全性

那么指令重排序会对安全性造成什么影响呢?

instance = new Singleton();

来看上面这行代码。对象的初始化,具体来说可以拆分为三个部分
1.分配对象内存空间
2.初始化对象
3.赋值给引用
而JVM在执行过程中为了保证效率等因素可能会进行重排序,如顺序变为132。这样操作对该线程本身是不会产生影响的,但如果在13之后,进入另一个线程,该线程判断instance将不为null(因为该引用已经指向了一块内存空间),就会导致异常。因此,加入volatile的另一个作用是为了禁止指令重排序
具体来说,volatile建立了一个内存屏障,屏障前的指令不能排序到屏障后,屏障后的指令不能排序到屏障前。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值