《Java并发编程实战》3.1节的一段代码:
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
按照书中所讲,这段代码不一定输出42,有可能陷入死循环。原因是代码中没有足够的同步机制,无法保证主线程写入的ready他number对读线程是可见的。也有可能是0,原因是“重排序”,读线程看到了主线程写入的ready却没有看到number。但是经过多次测试,始终输出42,既没有输出0,也没有死循环。为了验证书中所说的主线程修改对读线程不可见,我改写了代码:
public class NoVisibilityLoop {
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (true) {
System.out.println(number);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
}
}
public static void main(String[] args) throws InterruptedException {
new ReaderThread().start();
Thread.sleep(1000);
number = 42;
}
}
多次测试输出结果是:0000042424242这个结果说明了主线程写入的number对读线程是可见的。但是这本书的作者一堆大牛,不会搞错的。还请大家帮忙看看我的验证方法哪里出问题了,谢谢。运行环境:jdk 1.8.0_101,server模式。
4 回答
慕斯王
TA贡献1864条经验 获得超2个赞
原文的意思是让你重复多次运行这段代码
大概运行几十次甚至上百次,可能出现一次死循环,而这个在实际开发中是不可取的
而这是代码设计缺陷的问题,所以建议不要这么编程,要保持主副线程的同步性不要用这样的写法,你继续往后看,这书既然这么说,可能会有别的解决方案来帮你理解他描述的原理
慕桂英3389331
TA贡献2036条经验 获得超8个赞
首先测试多次正确也不能保证完全就是正确的,其次这本书是jdk5和6了,jdk8估计做了些优化,
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
@Override
public void run() {
int i=0;
while (!ready) {
i++;
// Thread.yield();
}
System.out.println(number);
}
}
public static void main(String[] args) throws Exception {
new ReaderThread().start();
TimeUnit.MILLISECONDS .sleep(9);
number = 42;
ready = true;
}
把 thread.yield 换成 i++ 或者 sleep 与否 结果都有差别
这种执行顺序是指令重排决定的,不用volatile没法保证
添加回答
举报
0/150
提交
取消