本文介绍了“重新排序和发生之前的关系是什么”的知识。很多人在实际案例的操作中会遇到这样的困难。让边肖带领你学习如何处理这些情况。希望大家认真阅读,学点东西! 在谈论重新排序之前,让我们看一个例子: inta=0,b=0;public void methodone(){ intone=a;b=1;} public void method two(){ int two=b;a=2;}应该不难看出,在上面的例子中,我定义了两个共享变量a和b,以及两个方法。第一种方法是将局部变量1赋给a,然后将b的值设置为1。第二种方法是将局部变量2赋给B,然后将A的值设置为2。 那么我这里有一个问题。(一,二)的价值是什么? 你可能会不假思索地告诉我它不是(0,1)就是(2,0),这取决于我的主方法先执行哪个方法。 是的,如果程序在单线程上运行,这个答案没有错。 但是如果它在多线程环境中呢? 假设方法一和方法二在两个不同的线程上执行。此时,Java虚拟机在执行任何方法的第一个赋值语句后切换线程。此时,(一,二)的值可能是(0,0)。 看到这里,你有什么疑惑吗?为什么,为什么我写的程序到了Java虚拟机,它就为我改变了? 因为在执行的过程中,发生了重新排序。它可能是及时编译器的重新排序、处理器的无序执行或内存系统的重新排序。 总之,在程序执行过程中,会发生重新排序,然后结果可能是(0,0)。 为什么会重排序 看完上面,你可能会奇怪为什么会有重新排序。 我的程序是按照我自己的逻辑写的,所以没有问题。为什么Java虚拟机会移动我的程序逻辑? 想想看,CPU和内存都是非常宝贵的资源。如果Java虚拟机重新排序后没有效果,肯定不会做这种吃力不讨好的事情。 那么,重新排序有什么好处呢? 重排序使得程序的性能得以提高 为了方便理解,我以生活中的场景为例。 当你早上起床的时候,你会穿衣、洗漱、做饭和吃饭,对吗?你起床后做了什么?洗的时候是不是先把饭煮好(比如让蒸蛋器给你蒸一个鸡蛋),然后洗完就可以直接吃早餐了。 你为什么要这么做?不仅仅是为了节省时间,你可以多睡一分钟,对吗? 同理,重新排序Java虚拟机的原因也是为了提高程序的性能。你写的程序很简单,只有一行代码,你可能需要在底层使用不同的硬件。比如一条指令需要同时使用CPU和打印机设备,但是此时CPU的任务完成了,但是打印机的任务还没有完成。这个时候该怎么办?不让CPU执行下一条指令?CPU的时间太宝贵了,你不让它工作。你确定你没有浪费它的生命吗? 因此,为了提高程序的利用率和性能,Java虚拟机会在您完全执行完这条指令之前执行另一条指令。这就是管道。 流水线最怕什么?我正在执行命令,执行命令,突然被打断了。恢复中断的成本非常高,所以我们必须尽最大努力绞尽脑汁,以免中断发生。 实时编译器的重新排序、处理器的无序执行和内存系统的重新排序都是为了减少中断。 此时,您是否熟悉Java虚拟机的重新排序? 重排序带来的问题 回到文章开头给出的例子,重新排序确实提高了CPU利用率和程序性能,但是我的程序得到的结果可能是错误的。这是不是有点得不偿失? 因为重排序可以保证串行语义一致性,所以没有义务保证多线程之间的语义一致性。 每一个问题都可以解决。如果没有,再想想。 怎么解决?有必要谈谈顺序一致内存模型和JMM (Java Memory Model)。 顺序一致性内存模型与 JMM 如果要谈数据一致性,就必须谈数据竞争。 什么是数据竞争?

在 Java 内存模型规范中给出了定义:

重排序和happens-before有什么关系 第1张