java - 关于重新排序:尽管使用了 volatile,为什么这段代码会抛出 RuntimeException?
问题描述
public class ReOrdering implements Runnable { int one, two, three, four, five, six; volatile int volaTile; @Override public void run() { one = 1; two = 2; three = 3; volaTile = 92; int x = four; int y = five; int z = six; } }
和的分配可以重新排序
one
,只要它们都发生在写入之前。类似地,当写入发生在所有语句之前, 可能会重新排序、、和语句。该操作通常称为内存屏障。发生之前保证确保 变量的读取和写入指令不能跨内存屏障重新排序。two
three
volatile
x
y
z
volatile
volatile
volatile
保证之前发生还有另一个影响:当线程写入
volatile
变量时,在写入变量之前由线程更改的所有其他变量(包括非易失性volatile
变量)也被刷新到主存储器。当一个线程读取一个volatile
变量时,它还会读取所有其他变量——包括非易失性变量——这些变量与volatile
变量一起被刷新到主内存。
© Bruce Eckel “关于 Java 8”
我一定误解了一些东西,因为这段代码不能这样工作
public class Reordering {
private int x;
private volatile int y;
public void writer() {
x = 1;
y = 2;
}
public void reader() {
if (y == 2) {
if(x == 0) {
// X assignment is happens-before for
// volatile Y assignment
// so X can't be 0 when Y equals 2
throw new RuntimeException();
}
x = 0;
y = 0;
}
}
public static void main(String[] args) {
Reordering reordering = new Reordering();
Thread thread = new Thread(() -> {
while (true) {
reordering.writer();
}
});
thread.setDaemon(true);
thread.start();
while (true) {
reordering.reader();
}
}
}
解决方案
我认为,当编写器刚刚设置x=1
,而读者已经在 if 块中(在变量分配之前)时,可能会出现问题:
reader writer state
----------------- ------ --------
stops before x=0 x=1, y=2
x=1 x=1, y=2
x=0 x=0, y=2
y=0 x=0, y=0
y=2 x=0, y=2
reader will throw
推荐阅读
- python - 在 python 中,如何为其中一列中列表的每个元素创建单独的行?
- r - 如果在 purrr 语言中不存在列,则添加列
- c++11 - 如果 C++ 中有引用参数,如何复制函数的参数?
- python - 为什么 pandas 会删除重复数据?
- sql - 查询一个或多个列具有值的多列
- php - 如何从 ajax $_POST 输出 PHP 数组并将值拆分或分解为键和值
- python - 使用 groupby 和 get_group 将一个数据帧分成几个数据帧
- vuejs2 - vue js页面上的谷歌分析加载时间
- javascript - React 高阶组件:我可以将 JSX 元素作为道具传递吗?
- python - 为什么我的 python 计数器没有给我一个范围内的特定字符?