首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >指令重排与发生前关系

指令重排与发生前关系
EN

Stack Overflow用户
提问于 2013-04-25 11:23:37
回答 1查看 13.9K关注 0票数 57

在实践中的Java并发一书中,我们多次被告知,我们的程序的指令可以由编译器、JVM在运行时重新排序,甚至可以由处理器重新排序。因此,我们应该假设,执行的程序不会按照与我们在源代码中指定的顺序完全相同的顺序执行其指令。

但是,最后一章讨论Java模型提供了一个happens-before规则列表,指示JVM保留了哪些指令顺序。这些规则中的第一条是:

  • “程序顺序规则。线程中的每一个动作都发生在该线程中的每一个动作之前,而该线程中的每个动作都是在程序顺序的后面出现的。”

我相信“程序顺序”指的是源代码。

我的问题:假设这个规则,我想知道什么指令实际上可能被重新排序。

“行动”的定义如下:

Java内存模型是根据操作指定的,包括对变量的读和写、监视器的锁和解锁,以及线程的启动和连接。JMM定义了程序中所有操作之前发生的偏序。为了确保执行操作B的线程能够看到操作A的结果(无论A和B是否发生在不同的线程中),必须在A和B之间的关系之前发生a。如果在两个操作之间排序之前没有发生,JVM可以随意重新排序它们。

提及的其他订单规则如下:

  • 监视锁定规则。监视器锁上的解锁发生在同一监视器锁上的每个后续锁之前。
  • 易失变量规则对易失性字段的写入发生在随后对该字段的每次读取之前。
  • 线程启动规则对线程上的Thread.start的调用发生在已启动线程中的每个操作之前。
  • 线程终止规则线程中的任何操作都发生在任何其他线程检测到线程已经终止之前,方法是成功地从Thread.join返回或通过Thread.isAlive返回false。
  • 中断规则。一个线程在另一个线程上调用中断发生在中断线程检测中断之前(通过抛出InterruptedException,或者调用isInterrupted或中断)。
  • 终结器规则。对象的构造函数的结束发生在该对象的终结器开始之前。
  • 传递性如果A发生在B之前,B发生在C之前,那么A发生在C之前。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-05-18 21:56:27

程序顺序规则的关键点是:线程中的

想象一下这个简单的程序(最初所有变量都是0):

T1:

代码语言:javascript
复制
x = 5;
y = 6;

T2:

代码语言:javascript
复制
if (y == 6) System.out.println(x);

从T1的角度来看,执行必须与y在x(程序顺序)之后被分配一致。然而,从T2的角度来看,情况并不一定如此,T2可能会打印0。

实际上允许T1首先分配y,因为两个分配是独立的,并且交换它们不影响t1的执行。

有了适当的同步,T2将始终打印5或不打印。

编辑

你似乎误解了节目顺序的含义。The program order rule boils down to

如果xy是同一个线程的操作,x按程序顺序出现在y之前,那么hb(x, y) (即x发生在y之前)。

以前在JMM中有一个非常特殊的含义。特别是,这并不意味着从墙上时钟的角度来看,y=6必须是x=5在T1中的后续。这只意味着T1执行的操作序列必须与该顺序一致。您也可以参考JLS 17.4.5

应该注意的是,在两个操作之间的关系发生之前,的存在并不一定意味着它们必须按照实现的顺序进行。如果重新排序会产生与合法执行一致的结果,则不违法。

在我前面给出的示例中,您将同意从T1的角度来看(即在一个线程程序中),x=5;y=6;y=6;x=5;是一致的,因为您不读取这些值。保证下一行的语句(在T1中)可以看到这两个操作,而不管它们的执行顺序如何。

票数 62
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16213443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档