@
az467 @
nlzy @
documentzhangx66 关于第二个问题:结论是对的,是我弄错了,sorry ;
我前面说能复现的代码是错的,代码如下:
class Scratch {
int a = 0;
boolean flag = false;
public static void main(String[] args) {
final Scratch scratch = new Scratch();
new Thread(() -> {
while (true) {
scratch.reader();
}
}).start();
new Thread(() -> {
while (true) {
scratch.writer();
}
}).start();
}
public void writer() {
flag = false;
a = 41;
a = 42;
flag = true;
}
public void reader() {
if (flag) {
if (a != 42) {
System.out.println("error!");
}
}
}
}
这里我搞错了,这里能打印出 a!=42 明显是线程切换导致的, 不能画蛇添足在上面再次为 a 赋值的。
一个值得提醒的现象:
示例代码中即使把 flag 的 volatile 去掉,a 的值也无法复现出 0 的情况(jdk7/jdk8 均不行),查资料说 x86cpu 不支持写重排序,x86cpu 的市场占有率那么高,所以大部分同学都无法复现,mac m1 的同学可以试试能不能复现
我的想法和 documentzhangx66 同学的是一样的,但是 volatile 的能力其实很强的,az467 发的那个文章写的很清楚了
最后,个人愚见,如 volatile 那么底层的工具,没有特殊的需求还是尽量少用,用更加上层的工具在开发和后续的维护上都更合适些