【你问我答】原子指令重排的底层原理是什么?

问题描述:

原子指令重排的底层原理是什么?

回答有奖:

选取一位认真回答问题的牛友,赠送200牛币!
▶回答尽量有自己的思考,不要单纯的只是复制粘贴定理定义,或者他人blog哦~

你问我答问题汇总:点击进入
关注你问我答栏目:点击关注

你问我答 - 答问题,成大佬,拿牛币!
你问我答是牛客新栏目,每周1期几个面试中真实遇到的问题,
牛友在问题贴下留下自己的知识,经验与见解,
帮助更多牛友了解更多技术相关知识!
#悬赏##Java工程师##面试题目#
全部评论
1.原子性操作       在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行。只有简单的读取、赋值(而且必须是将数字赋值给某个变量,变量之间的相互赋值不是原子操作)才是原子操作。   在32位平台下,对64位数据的读取和赋值是需要通过两个操作来完成的,不能保证其原子性。但是好像在最新的JDK中,JVM已经保证对64位数据的读取和赋值也是原子性操作了。     Java内存模型只保证了基本读取和赋值是原子性操作,如果要实现更大范围操作的原子性,可以通过synchronized和Lock来实现。由于synchronized和Lock能够保证任一时刻只有一个线程执行该代码块,那么自然就不存在原子性问题了,从而保证了原子性。 2.指令重排 一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。 虽然处理器会对指令进行重排序,但是它会保证程序最终结果会和代码顺序执行结果相同,处理器在进行重排序时是会考虑指令之间的数据依赖性,如果一个指令Instruction 2必须用到Instruction 1的结果,那么处理器会保证Instruction 1会在Instruction 2之前执行。 虽然重排序不会影响单个线程内程序执行的结果,但是多线程呢?如果语句1和语句2没有数据依赖性,因此可能会被重排序。假如发生了重排序,在线程1执行过程中先执行语句2,而此是线程2会以为初始化工作已经完成,那么就会跳出while循环,去执行doSomethingwithconfig(context)方法,而此时context并没有被初始化,就会导致程序出错。 从上面可以看出,指令重排序不会影响单个线程的执行,但是会影响到线程并发执行的正确性。
1 回复
分享
发布于 2020-04-28 19:52
指令间存在数据相关 控制相关 指令相关 这是计算机综合里的东西
点赞 回复
分享
发布于 2020-04-28 11:17
英特尔
校招火热招聘中
官网直投
假设一台计算机配备两个CPU,在每个CPU中,cache 按地址被分成了两块 cache banks,分别是cache bank0 和 cache bank1。 举个理想的内存访问指令顺序例子: 1,CPU0往cache address 0×12345000 写入一个数字 1。因为address 0×12345000是偶数,所以值被写入 bank0. 2,CPU1读取 bank0 address 0×12345000 的值,即数字1。 3,CPU0往 cache 地址 0×12345100 写入一个数字 2。因为address 0×12345100是奇数,所以值被写入 bank1. 4,CPU1读取 bank1 address 0×12345100 的值,即数字2。 重排序后的内存访问指令顺序: 1,CPU0 准备往 bank0 address 0×12345000 写入数字 1。 2,CPU0检查 bank0 的可用性。发现 bank0 处于 busy 状态。 3,CPU0 为了防止 cache等待,发挥最大效能,将内存访问指令重排序。即先执行后面的 bank1 address 0×12345100 数字2的写入请求。 4,CPU0检查 bank1 可用性,发现bank1处于 idle 状态。 5,CPU0 将数字2写入 bank 1 address 0×12345100。 6,CPU1来读取 0×12345000,未读到 数字1,出错。 7,CPU0 继续检查 bank0 的可用性,发现这次bank0 可用了,然后将数字1写入 0×12345000。 8,CPU1 读取 0×12345100,读到数字2,正确。 可以看到第 3 步发生了指令重排序,并导致第 6步读到错误的数据。通过对指令重排,CPU可以获得更快地响应速度。重排序是为了优化性能,但是不管怎么重排序,单线程下程序的执行结果不能被改变。 内存屏障是用来防止CPU出现指令重排序的利器之一,一般在Java中,我们可以使用volatile来修饰变量,volatile底层就是使用到了内存屏障。 内存屏障会提供3个功能: 1.在执行到内存屏障这句指令时,在它前面的操作已经全部完成; 2.它会强制将对缓存的修改操作立即写入主存; 3. 如果是写操作,它会导致其他CPU中对应的缓存行无效。
点赞 回复
分享
发布于 2020-04-28 19:37

相关推荐

1 2 评论
分享
牛客网
牛客企业服务