java并发编程之指令重排序问题

正所谓耳听为虚,但是眼见也不一定为实。

在java底层的一些运行机制上便是如此。

关于指令重排序

我一句话的理解就是:处理器和编译器为了提高并行度和系统性能,会将没有相互依赖的指令进行重新排序然后再执行。

其实就是说,不管你代码写的再乱,逻辑再不清晰,我jvm也得找一条我认为舒服的方式来运行你的代码

jvm认为没有相互依赖的指令换换位置也没啥影响吗,更何况我认为这样执行代码的姿势更为舒服,何乐而无为呢。

当然这是站在单个线程的角度来考虑这个问题的,就像一个人睡一张床再怎么变换姿势又不会有啥影响,但是多线程
情况下操作的是同一个内存模型的话,是很有可能影响到另一个线程的。

姑且看下面这个例子。

public class Test {
    public int a = 0;
    public boolean flag = false;
    public int i;
    public void writer() {
        a = 1;          //指令1
        flag = true;    //指令2
    }
    public void reader() {
        if(flag) {     //指令3
            i =  a * a; //指令4
        }
    }
    public static void main(String[] args) {
        Test test = new Test();
      new Thread(){
          public void run() {
              test.writer();
          }
      }.start();
        new Thread(){
            public void run() {
                test.reader();
            }
        }.start();
        try {
            Thread.sleep(1000);
            System.out.println(test.flag+":"+test.i+":"+test.a);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

一个线程操作的是1和2指令,另一个线程操作的是其他指令。
正常情况下输出结果

true:1:1

如果第一个线程变换了姿势,先执行指令2然后让第二线程执行指令3和4那么结果就会是这样

true:0:1

当然还有一方面,指令3和指令4具有相互依赖性,因此本身并不能进行指令重排序,但是处理器和编译器为了保证序列执行的并行度,会进行预测执行,即先计算出a*a的值并且将改值存入到一个叫重排序缓存的硬件缓存中,当flag满足条件时再将改值赋给后来定义的i,这样也能出现0:true的结果。

这就是一个简单的指令重排序的问题。

哦,对了,我记得加上volatile就可以固定好你们的姿势

public volatile int a = 0;
public volatile boolean flag = false;

这样你们就可以老老实实了。

参考资料
java并发变成的艺术 ----方腾飞著

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值