在 Java Concurrency In Practice 一书中,我们多次被告知,程序的指令可以由编译器、运行时的 JVM 甚至处理器重新排序。所以我们应该假设执行的程序不会以与我们在源代码中指定的顺序完全相同的顺序执行其指令。
但是,讨论 Java 内存模型的最后一章提供了一系列发生前发生的规则,指示 JVM 保留了哪些指令顺序。这些规则中的第一个是:
- “程序顺序规则。线程中的每个操作都发生在该线程中程序顺序后面的每个操作之前。”
我相信“程序顺序”是指源代码。
我的问题:假设这条规则,我想知道实际上可以重新排序什么指令。
“动作”定义如下:
Java 内存模型是根据操作指定的,包括对变量的读取和写入、监视器的锁定和解锁以及启动和加入线程。JMM 定义了一个偏序,称为发生在程序中的所有操作之前。为了保证执行action B的线程可以看到action A的结果(无论A和B是否发生在不同的线程中),A和B之间必须有happens before关系。在没有ahappens before ordering的情况下,两个之间的排序操作时,JVM 可以随意对它们进行重新排序。
其他提到的订单规则是:
- 监控锁定规则。监视器锁上的解锁发生在同一监视器锁上的每个后续锁之前。
- 易变的变量规则。对 volatile 字段的写入发生在对同一字段的每次后续读取之前。
- 线程开始规则。对线程的 Thread.start 调用发生在已启动线程中的每个操作之前。
- 线程终止规则。线程中的任何操作发生在任何其他线程检测到该线程已终止之前,要么通过从 Thread.join 成功返回,要么通过 Thread.isAlive 返回 false。
- 中断规则。一个线程在另一个线程上调用中断发生在被中断的线程检测到中断之前(通过抛出 InterruptedException,或者调用 isInterrupted 或中断)。
- 终结器规则。对象的构造函数的结束发生在该对象的终结器开始之前。
- 传递性。如果 A 发生在 B 之前,B 发生在 C 之前,那么 A 发生在 C 之前。