多线程_高级主题_happenbefore_指令重排

HappenBefore:发生之前。
当我们写的这个代码,没有按你编写的位置或者没有按你期望的顺序执行的时候,显然就是它指定的位置调换了。为什么调换?因为编译器和CPU会尝试重排指令,使代码更快的运行提高性能,一般发生在代码跟代码之间没有相互的直接联系,没有相互的依赖,我把后面的代码向前提不影响我整个的结果,这一块我们就叫做指令重排或者重排指令。一般来说,我们编写的这个代码需要翻译【编译】成机器码,那编译的时候会决定哪个变量用哪个存储器,或者用哪个寄存器,之后就翻译成机器指令了,比如说图片中的三句话,我们翻译成机器指令,这就叫汇编了,同时要决定它存在哪个地方,比如说图片中有那么多值,我们要把这个值存好,为我们下一步做准备。
在这里插入图片描述
下面就用这三句话来理解一下机器是怎么编译和执行代码的。

第一步:获取指令,叫fetch the instruction。
在这里插入图片描述

第二步:解码指令并获取寄存器值,decode the instruction & fetch register values。主存和工作内存要进行拷贝。
在这里插入图片描述
第三步:执行操作,execute the operation。
在这里插入图片描述
第四步:写回结果,write back the result。将操作的结果同步到主存里面。
在这里插入图片描述
总结:计算机芯片在执行指令的时候肯定要拆成多个步骤,要拆成多个步骤这个CPU才能得到充分的利用,一般来说指令的步骤如下:【从内存里面拿到一条指令,指令进行解码,再从寄存器【主存】里面拿值开始计算结果,将这个结果写回到寄存器,这是一条指令执行的步骤】
在这里插入图片描述
现在问题来了,当我们执行下一条指令的时候,指令是将“和”subTotal加到total上,然后将标识位isDone设为true。这里的求和看似简单,但可能它有延时、也可能这个“和”是来自于其他的结果等,所以这个值的“求和”在写回主存的那一刻可能比较慢,这个时候CPU就不愿意等了,它就会看看下一个指令和求和有没有关系,没有关系的话,CPU就将下一个指令提前了,这个指令就为真了【isDone=true】。注意此时这个求和的值还没有写回来。那如果是在多线程环境下,有一个地方在使用isDone,那是不是就为真了,可能就运行起来了,然后同时这个多线程里面可能在操作total,那这个值可能就不是我要的那个值了。所以指令重排对于多线程肯定是有影响的。这里的isDone和上一条指令是没有关系的,CPU为了提高性能将它提前,提前可能就存在问题了,如果是单线程那没有问题,因为最终你肯定要等total+=subTotal这个值回来,但是多线程我们就直接看主存中的结果了,所以在多线程环境下指令重排是会影响我们的结果的。
在这里插入图片描述
在这里插入图片描述

package com.sxt.others;
/**
 * 指令重排: 代码执行顺序与预期不一致
 * 目的:提高性能
 * 
 * @author 
 *
 */
public class HappenBefore {
	//变量1
	private  static int a = 0;
	//变量2
	private static boolean flag = false;
	public static void main(String[] args) throws InterruptedException {
		for(int i=0;i<10;i++) {
			a = 0;
			flag = false;
			
			//线程1 更改数据
			Thread t1 = new Thread(()->{
				a = 1;
				flag = true;
			}) ;
			//线程2 读取数据
			Thread t2 = new Thread(()->{
				if(flag) {
					a *=1;
				}
				//指令重排
				if(a == 0) {
					System.out.println("happen before a->"+a);
				}
			}) ;
			
			t1.start();
			t2.start();
			
			//合并线程
			t1.join();
			t2.join();
		}
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值