java多线程可见性问题
《java并发编程实战》一书中第三章 可见性章节中说
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;
}
}
“该代码可能会输出0,也可能持续循环下去,因为读线程可能永远都看不到ready的值”
输出0,还能理解,因为number没有加volatile。
为什么可能“永远都看不到ready的值”?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
跟
number
一样啊一直读的是本线程内存,缓存的false
值可以读另外一本叫《java并发编程的艺术》了解为什么,大概意思就是没有加volatile的话,和可能这个cache一直是线程cache,前年校招的时候读过一次。。
大致可以理解主线程只要一直不刷新ready的值,ReaderThread就一直认为ready的值为false,主要是理解volatile变量的意义,还有一个因素就是线程调度,yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
我看这个volatile相关文章不下于五篇 感觉都不是说的太好 相似度很高 我先说一下自己的理解 每一个线程都对应一个主存空间 例如你例子中的number 第一次时 从主存中读取number的值 然后把它放进一个缓存cache中 从单线程中看 是没问题的 但是在多线程中 如果对这个number做了读写操作 那么就会出现数据的不一致性 例如 线程1 从主存中读取number=10 放进缓存中 线程2读取缓存中的number值等于10然后进行加减操作 再还没有写进主存时 线程3又读取了缓存中的值 还是10!!! 加volatile关键字保证数据的可见性我是这样理解的 就是每次这个number发生变化时 都会对其他读取number值的线程发出警告 告诉它们 这个值发生变化了 你要去主存中获取最新的值 实际上还可能出现数据不一致问题 因为警告只是警告 并没有限制线程进行的操作而已 还有一个是禁止指令重排序在多线程中对结果产生的影响(这个东西可以去看看相关文章 jvm里面的方法了) volatile相较于Synchronized是一种轻量级的保证数据同步的修饰符 以上供你参考 顺带提一句 我看spring源码里面 目前看见的volatile关键字修饰的都是类级别的属性 例如 volatile class<?> xxx这类的 所以感觉各种博客把volatile放一个时常变化的基础数据类型变量上做例子 是不是欠考量了