“Java 重排序对多线程的影响”的版本间的差异
跳到导航
跳到搜索
Jihongchang(讨论 | 贡献) (建立内容为“<syntaxhighlight lang="java"> public class ReorderExample { int a = 0; boolean flag = true; public void writer() { a = 1; // 1 flag…”的新页面) |
Jihongchang(讨论 | 贡献) |
||
第25行: | 第25行: | ||
'''<big>答案是:不一定能看到</big>'''。 | '''<big>答案是:不一定能看到</big>'''。 | ||
+ | === 操作 1 和 操作 2 重排序 === | ||
由于操作 1 和操作 2 没有数据依赖关系,编译器和处理器可以对这两个操作重排序; | 由于操作 1 和操作 2 没有数据依赖关系,编译器和处理器可以对这两个操作重排序; | ||
第30行: | 第31行: | ||
当操作 1 和操作 2 重排序时,可能会产生什么效果?看下图: | 当操作 1 和操作 2 重排序时,可能会产生什么效果?看下图: | ||
+ | [[文件:重排序程序执行时序图3.png|无|缩略图|494x494像素|虚箭线标识错误的读操作]] | ||
+ | |||
+ | |||
+ | 如图所示,操作 1 和 操作 2 做了重排序。 | ||
+ | |||
+ | 程序执行时,线程 A 首先写标记变量 flag,随后线程 B 读这个变量。 | ||
+ | |||
+ | 由于条件判断为真,线程 B 将读取变量 a。 | ||
+ | |||
+ | 此时,变量 a 还没有被线程 A 写入,在这里多线程程序的语义就被重排序破坏了。 | ||
+ | |||
+ | |||
+ | |||
+ | === 操作 3 和操作 4 重排序 === | ||
+ | 下面看看当操作 3 和 操作 4 重排序时会产生什么效果(借助这个重排序,可以顺便说明控制依赖性)。 |
2023年3月2日 (四) 03:10的版本
public class ReorderExample {
int a = 0;
boolean flag = true;
public void writer() {
a = 1; // 1
flag = true; // 2
}
public void reader() {
if (flag) { // 3
int i = a * a;
}
}
}
flag 变量是个标记,用来标识变量 a 是否已被写入。
这里假设有两个线程 A 和 B,A 首先执行 writer() 方法,随后 B 线程接着执行 reader() 方法。
线程 B 在执行操作 4(int i = a * a;
)时,能否看到线程 A 在操作 1(a = 1;
) 对共享变量 a 的写入呢?
答案是:不一定能看到。
操作 1 和 操作 2 重排序
由于操作 1 和操作 2 没有数据依赖关系,编译器和处理器可以对这两个操作重排序;
同样,操作 3 和操作 4 没有数据依赖关系,编译器和处理器也可以对这两个操作重排序。
当操作 1 和操作 2 重排序时,可能会产生什么效果?看下图:
如图所示,操作 1 和 操作 2 做了重排序。
程序执行时,线程 A 首先写标记变量 flag,随后线程 B 读这个变量。
由于条件判断为真,线程 B 将读取变量 a。
此时,变量 a 还没有被线程 A 写入,在这里多线程程序的语义就被重排序破坏了。
操作 3 和操作 4 重排序
下面看看当操作 3 和 操作 4 重排序时会产生什么效果(借助这个重排序,可以顺便说明控制依赖性)。