java多线程可见性问题

发布于 2022-09-06 12:50:43 字数 643 浏览 27 评论 0

《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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

千秋岁 2022-09-13 12:50:43

number一样啊一直读的是本线程内存,缓存的false

后来的我们 2022-09-13 12:50:43

可以读另外一本叫《java并发编程的艺术》了解为什么,大概意思就是没有加volatile的话,和可能这个cache一直是线程cache,前年校招的时候读过一次。。

白色秋天 2022-09-13 12:50:43

大致可以理解主线程只要一直不刷新ready的值,ReaderThread就一直认为ready的值为false,主要是理解volatile变量的意义,还有一个因素就是线程调度,yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。

幽梦紫曦~ 2022-09-13 12:50:43

我看这个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放一个时常变化的基础数据类型变量上做例子 是不是欠考量了

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文