并发实战——理解JVM中的Happens-Before规则(可见性,volatile,双重检验锁)

在解释该规则之前,我们先看一段多线程访问数据的代码例子:public class Test1 { private int a=1, b=2; public void foo(){ // 线程1 a=3; b=4; } public int getA(){ // 线程2 return a; } pu
摘要由CSDN通过智能技术生成

在解释该规则之前,我们先看一段多线程访问数据的代码例子:

public class Test1 {
    private int a=1, b=2;

    public void foo(){  // 线程1 
        a=3;
        b=4;
    }

    public int getA(){ // 线程2
        return a;
    }    
    public int getB(){ // 线程2
        return b;
    }
}

上面的代码,当线程1执行foo方法的时候,线程2访问getA和getB会得到什么样的结果?
答案:

A:a=1, b=2  // 都未改变
B:a=3, b=4  // 都改变了
C:a=3, b=2  //  a改变了,b未改变
D:a=1, b=4  //  b改变了,a未改变

上面的A,B,C都好理解,但是D可能会出乎一些人的预料。
一些不了解JMM的同学可能会问怎么可能 b=4语句会先于 a=3 执行?

这是一个多线程之间内存可见性(Visibility)顺序不一致的问题。有两种可能会造成上面的D选项。


  1. Java编译器的重排序(Reording)操作有可能导致执行顺序和代码顺序不一致。
    关于Reording:

Java语言规范规定了JVM要维护内部线程类似顺序化语义(within-thread as-is-serial semantics):只要程序的最终结果等同于它在严格的顺序化环境中执行的结果,那么上述所有的行为都是允许的。

简单的说:假设代码有两条语句,代码顺序是语句1先于语句2执行;那么只要语句2不依赖于语句1的结果,打乱它们的顺序对最终的结果没有影响的话,那么真正交给CPU去执行时,他们的顺序可以是没有限制的。可以允许语句2先于语句1被CPU执行,和代码中的顺序不一致。

重排序(Reordering)是JVM针对现代CPU的一种优化,Reordering后的指令会在性能上有很大提升。(不知道这种优化对于多核CPU是否更加明显,也或许和单核多核没有关系。)

因为我们例子中的两条赋值语句,并没有依赖关系,无论谁先谁后结果都是一样的,所以就可能

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值