并发编程的三大挑战之有序性及其解决方案

  

目录

  

一、有序性产生的原因

 二、怎么解决上面的有序性问题


一、有序性产生的原因

编译优化导致的指令重排带来有序性问题

 有序性指定的是程序按照代码的先后顺序执行。而编译器为了优化性能,有时候会改变程序中语句的先后顺序,例如: a =6;b=7,编译器优化后可能编程了b=7;a=6。在这个例子里,编译器调整了语句的顺序,但不会影响到最终结果。

        在java领域中经典案例利用双重检查创建单例对象,例如下面的代码:在获取实例的getInstance()方法中,我们先判断instance是否为空,如果为空则锁定Singletion.class并再次检查intance是否为空,如果还为空就创建一个Singleton的实例。

private static Singleton instance;

private Singleton (){}

public static Singleton getInstance(){
    // B
    if(instance== null){
        synchronized (Singleton.class){

            if(instance== null){
                // A   ,  开辟空间,instance指向地址,初始化
                instance= new Singleton ();
            }
        }
    }
    return instance;
}

上面的代码有什么问题吗?看起来很完美,但是问题出现在instance= new Singleton ();语句,该语句会执行三个操作,1、开辟空间  2、初始化  3、instance指向地址 

如果按照正常顺序来说也不会有问题,但是指令2和指令3之间不存在依赖关系,编译器优化后可能产生重排,执行顺序为1 --> 3  --> 2,那么这个时候可能会产生在A线程刚把instance指向对应地址后,B线程获取到执行权,然后获取到一个没有初始化的对象,从而产生空指针异常。A、B两个线程的执行顺序如下:

 二、怎么解决上面的有序性问题

实际上我们只要解决了指令重排,就可以解决这个有序性问题。那么我们可以通过添加关键字volatile来解决,如下所示:

private static volatile Singleton instance;

private Singleton (){}

public static Singleton getInstance(){
    // B
    if(instance== null){
        synchronized (Singleton.class){

            if(instance== null){
                // A   ,  开辟空间,instance指向地址,初始化
                instance= new Singleton ();
            }
        }
    }
    return instance;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值