download:WEB前端线上系统课2022最新【已更新至916集day52】
JMM的设计
现在就来看看“先行发生”原则指的是什么。先行发生是 Java 内存模型中定义的两项操作之间的偏序关系,比如说操作A先行发生于操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。这句话不难理解,但它意味着什么呢?我们通过一个简单的案例来进行演示。
double pi = 3.14; // A
double r = 1.0; // B
double area = pi * r * r; // C
复制代码
上述代码用来计算圆的面积,存在3个 happens-before 关系,如下。
- A happens-before B
- B happens-before C
- A happens-before C
在3个 happens-before 关系中,2和3是必需的,但1是不必要的。因此,JMM 把 happens-before 要求禁止的重排序分为了下面两类。
- 会改变程序执行结果的重排序。
- 不会改变程序执行结果的重排序。
JMM 对这两种不同性质的重排序,采取了不同的策略,如下。
- 对于会改变程序执行结果的重排序,JMM要求编译器和处理器必须禁止这种重排序。
- 对于不会改变程序执行结果的重排序,JMM对编译器和处理器不做要求(JMM允许这种重排序)。
综合来看,JMM 其实是在遵循一个基本原则:只要不改变程序的执行结果(指的是单线程程序和正确同步的多线程程序),编译器和处理器怎么优化都行。例如,如果编译器经过细致的分析后,认定一个锁只会被单个线程访问,那么这个锁可以被消除,我们之前学习 JIT 编译器时有提到。