java java中的指令重新排序和发生在关系之前
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16213443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Instruction reordering & happens-before relationship in java
提问by Martin
In the book Java Concurrency In Practice, we are told several time that the instructions of our program can be reordered, either by the compiler, by the JVM at runtime, or even by the processor. So we should assume that the executed program will not have its instructions executed in exactly the same order than what we specified in the source code.
在 Java Concurrency In Practice 一书中,我们多次被告知我们程序的指令可以由编译器、运行时的 JVM 甚至处理器重新排序。因此,我们应该假设执行的程序不会以与我们在源代码中指定的完全相同的顺序执行其指令。
However, the last chapter discussing Java Memory Model provides a listing of happens-beforerules indicating which instruction ordering are preserved by the JVM. The first of these rules is:
然而,讨论 Java 内存模型的最后一章提供了先发生规则列表,指示 JVM 保留哪些指令顺序。这些规则中的第一个是:
- "Program order rule. Each action in a thread happens before every action in that thread that comes later in the program order."
- “程序顺序规则。线程中的每个操作都发生在该线程中程序顺序中稍后出现的每个操作之前。”
I believe "program order" refers to the source code.
我相信“程序顺序”是指源代码。
My question: assuming this rule, I wonder what instruction may be actually reordered.
我的问题:假设这个规则,我想知道实际上可能重新排序什么指令。
"Action" is defined as follow:
“动作”定义如下:
The Java Memory Model is specified in terms of actions, which include reads and writes to variables, locks and unlocks of monitors, and starting and joining with threads. The JMM defines a partial ordering called happens before on all actions within the program. To guarantee that the thread executing action B can see the results of action A (whether or not A and B occur in different threads), there must be a happens before relationship between A and B. In the absence of a happens before ordering between two operations, the JVM is free to reorder them as it pleases.
Java 内存模型是根据操作来指定的,其中包括对变量的读取和写入、监视器的锁定和解锁以及线程的启动和加入。JMM 定义了一个偏序,在程序中的所有操作上调用发生在之前。为了保证执行动作B的线程可以看到动作A的结果(无论A和B是否发生在不同的线程中),A和B之间必须有一个happens before关系。在没有ahappen before ordering的情况下,两者之间操作,JVM 可以随意重新排序它们。
Other order rules mentionned are:
提到的其他订单规则是:
- Monitor lock rule. An unlock on a monitor lock happens before every subsequent lock on that same monitor lock.
- Volatile variable rule. A write to a volatile field happens before every subsequent read of that same field.
- Thread start rule. A call to Thread.start on a thread happens before every action in the started thread.
- Thread termination rule. Any action in a thread happens before any other thread detects that thread has terminated, either by successfully return from Thread.join or by Thread.isAlive returning false.
- Interruption rule. A thread calling interrupt on another thread happens before the interrupted thread detects the interrupt (either by having InterruptedException thrown, or invoking isInterrupted or interrupted).
- Finalizer rule. The end of a constructor for an object happens before the start of the finalizer for that object.
- Transitivity. If A happens before B, and B happens before C, then A happens before C.
- 监视器锁定规则。监视器锁上的解锁发生在同一监视器锁上的每个后续锁之前。
- 可变变量规则。对 volatile 字段的写入发生在对该同一字段的每次后续读取之前。
- 线程启动规则。对线程的 Thread.start 调用发生在已启动线程中的每个操作之前。
- 线程终止规则。线程中的任何操作都发生在任何其他线程检测到线程已终止之前,无论是通过从 Thread.join 成功返回还是通过 Thread.isAlive 返回 false。
- 中断规则。在被中断的线程检测到中断之前,在另一个线程上调用中断的线程发生(通过抛出 InterruptedException 或调用 isInterrupted 或中断)。
- 终结者规则。对象构造函数的结束发生在该对象的终结器开始之前。
- 传递性。如果 A 在 B 之前发生,B 在 C 之前发生,那么 A 在 C 之前发生。
回答by assylias
The key point of the program order rule is: in a thread.
程序顺序规则的关键点是:在一个线程中。
Imagine this simple program (all variables initially 0):
想象一下这个简单的程序(所有变量最初都是 0):
T1:
T1:
x = 5;
y = 6;
T2:
T2:
if (y == 6) System.out.println(x);
From T1's perspective, an execution must be consistent with y being assigned after x (program order). However from T2's perspective this does not have to be the case and T2 might print 0.
从 T1 的角度来看,执行必须与在 x 之后分配的 y 一致(程序顺序)。然而,从 T2 的角度来看,情况并非如此,T2 可能会打印 0。
T1 is actually allowed to assign y first as the 2 assignements are independent and swapping them does not affect T1's execution.
T1 实际上允许先分配 y,因为这 2 个分配是独立的,交换它们不会影响 T1 的执行。
With proper synchronization, T2 will always print 5 or nothing.
通过适当的同步,T2 将始终打印 5 或不打印。
EDIT
编辑
You seem to be misinterpreting the meaning of program order. The program order rule boils down to:
您似乎误解了程序顺序的含义。程序顺序规则归结为:
If
x
andy
are actions of the same thread andx
comes beforey
in program order, thenhb(x, y)
(i.e.x
happens-beforey
).
如果
x
和y
是同一个线程的动作并且按程序顺序x
出现在之前y
,则hb(x, y)
(即x
发生在之前y
)。
happens-beforehas a very specific meaning in the JMM. In particular, it does notmean that y=6
must be subsequent to x=5
in T1 from a wall clock perspective. It only means that the sequence of actions executed by T1 must be consistent withthat order. You can also refer to JLS 17.4.5:
发生在 JMM 中具有非常具体的含义。特别是,它不意味着y=6
必须之后x=5
在T1从挂钟透视。这只意味着 T1 执行的动作顺序必须与该顺序一致。你也可以参考JLS 17.4.5:
It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.
应该注意的是,两个动作之间存在发生之前的关系并不一定意味着它们必须在实现中按该顺序发生。如果重新排序产生与合法执行一致的结果,则不违法。
In the example I gave above, you will agree that from T1's perspective (i.e. in a single threaded program), x=5;y=6;
is consistent with y=6;x=5;
since you don't read the values. A statement on the next line is guaranteed, in T1, to see those 2 actions, regardless of the order in which they were performed.
在我上面给出的示例中,您会同意从 T1 的角度(即在单线程程序中),由于您不读取值,x=5;y=6;
因此与 一致y=6;x=5;
。下一行的语句保证在 T1 中看到这 2 个操作,而不管它们的执行顺序如何。