Java 懒汉模式之Volatile优化

很多懒汉模式写成如下模式:

public class LazySingle {

    private static LazySingle single;

    private LazySingle(){}

    public static LazySingle getInstance(){
        if(single == null){
            synchronized (LazySingle.class) {
            //对类对象加锁,所有对象均不能同时运行。
                if(single == null){
                    single = new LazySingle();
                }
            }
        }
        return single;
    }
}

这里分析多线程下的情况。

主要问题在于 single = new LazySingle(); 这句,这并非一个原子操作,这段代码其实是分为三步执行:

  1. 为 LazySingle 分配内存空间,对内存清零
  2. 执行 LazySingle 的构造函数,初始化对象
  3. 将 single 指向分配的内存地址(执行完这步 single就为非 null 了)

看起来并没有问题,想想,在多线程下也没有问题,但这里有个坑,那就是指令重排序的问题。

由于CPU运行速度远比内存快,所以为了优化Java运行速度,在没有数据依赖性的前提下,编译器可能对指令重排序,先执行CPU自己就可以执行的指令。这种优化对单线程没有影响,对多线程可能产生影响。

也就是说这三步发生的前后顺序不能保证,不符合先行发生原则。执行顺序有可能变成 1>3>2。

例如,线程 T1 执行了 1 和 3,此时线程 T2 调用 getInstance() 后发现 single 不为空,因此返回 single,但此时 single 还未被初始化。(因为 Lazysingle 的构造函数还未执行)

解决方法就是将 single 变量声明成 volatile ,让其符合JMM中先行发生原则volatile 变量规则

public class LazySingle {

    private volatile static LazySingle single;

    private LazySingle(){}

    public static LazySingle getInstance(){
        if(single == null){
            synchronized (LazySingle.class) {
            //对类对象加锁,所有对象均不能同时运行。
                if(single == null){
                    single = new LazySingle();
                }
            }
        }
        return single;
    }
}

这里 volatile 可以禁止指令重排序。“也就是说,在 volatile 变量的赋值操作后面会有一个内存屏障(生成的汇编代码上),读操作不会被重排序到内存屏障之前。”

volatile的更多详细内容 -> 查找本博客中的另一篇文章 Java 中 volatile 关键字解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值