Java并发编程艺术 - 重排序

重排序是编译器和处理器为优化程序性能而对指令进行重新排序的手段。

数据依赖性

  • 写后写;a=1,a=2
  • 写后读;a=1,b=a
  • 读后写;a=b,b=1

以上三种情况存在数据依赖,重排将会引起结果改变。

as-if-serial

不管怎么重排序,但不能影响结果,编译器、runtime和处理器都必须遵守这个语义,即可以对不存在数据依赖关系的指令进行重排。

例如

1
2
3
int a=1;//操作1
int b=2;//操作2
int c=a+b;//操作3

以上操作1和2可以重排。

重排对多线程的影响

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ReorderExample {
int a = 0;
boolean flag = false;
public void writer() {
a = 1; // 1
flag = true; // 2
}
public void reader() {
if (flag) { // 3
int i = a * a; // 4
……
}
}
}

在多线程开发中:

  • 如果线程1对操作1和2进行重排,线程2执行reader的操作3时,变量a可能没有及时同步,结果可能为0而不是1。
  • 如果线程1对操作3和4进行重排,先将操作4结果暂存缓存,等待操作3决定是否缓存写入i;在单线程没有问题,但多线程操作3可能会被改变。

因此,多线程开发需要考虑程序执行的顺序性,可以采用同步原语,包括valatile、synchronized和final。

------ 本文结束------

本文标题:Java并发编程艺术 - 重排序

文章作者:Perkins

发布时间:2019年05月29日

原始链接:https://perkins4j2.github.io/posts/35014/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。