V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dengsq
V2EX  ›  Java

请教一个 Java volatile 字段可见性的问题

  •  
  •   dengsq · 2020-05-17 19:05:50 +08:00 · 2361 次点击
    这是一个创建于 1411 天前的主题,其中的信息可能已经有所发展或是发生改变。

    看一个讲解 volatile 可见性教学视频的时候,发现视频中的代码和我运行的效果不太一样,有些困惑。

    代码大致如下: https://gist.github.com/dsq123/e57514ca51c875b75d0ea311bb556d92

    视频中运行的效果是: 1.number 字段不加 volatile,主线程的循环会一直运行,读不到 number 字段的改变。 2.而加了 volatile 后,number 字段就可见了,程序则会正常结束。

    我测试的效果是,不加 volatile 关键字的情况下,主线程依旧可以获取到 AAA 线程对 number 的修改,这是为何?

    第 1 条附言  ·  2020-05-17 19:50:31 +08:00
    测试时在主线程里面打印了日志,所以才出现了此问题。现在搞清楚了,感谢一楼大哥
    while (mt.number == 0) {
    // System.out.println...
    }
    12 条回复    2020-05-19 08:10:43 +08:00
    luozic
        1
    luozic  
       2020-05-17 19:21:04 +08:00
    System.out.println 对这个有影响
    luozic
        2
    luozic  
       2020-05-17 19:22:34 +08:00   ❤️ 2
    yanshenxian
        3
    yanshenxian  
       2020-05-17 19:42:33 +08:00
    @luozic 感觉不太对 我本地没有复现题主所说的 不加 volatile 主线程可以获取到 AAA 线程对 number 修改的情况
    dengsq
        4
    dengsq  
    OP
       2020-05-17 19:47:17 +08:00
    @luozic 确实是这样,是 System.out.println 所影响的。
    dengsq
        5
    dengsq  
    OP
       2020-05-17 19:48:45 +08:00
    @yanshenxian 是我的疏忽,我测试时,在主线程的循环里打印了日志,所以读到了其他线程的改动。 然而我贴代码的时候,把主线程的 Sout 删掉了=。=
    yanshenxian
        6
    yanshenxian  
       2020-05-17 19:53:21 +08:00
    @dengsq get 了
    Jooooooooo
        7
    Jooooooooo  
       2020-05-17 20:11:42 +08:00
    不写 volatile 行为不定义
    dengsq
        8
    dengsq  
    OP
       2020-05-17 23:49:50 +08:00
    @luozic @yanshenxian @Jooooooooo 还想请教一个问题:
    有一种场景是 [A 线程指令重排导致 B 线程出错] ,如 A 改变了 boolean flag = true/false,而 B 线程需要根据 flag 处理逻辑。

    既然 volatile 可以保证变量的可见性,那么不加 volatile 时,不同线程之间的变量应该是不可见的。

    这样的话,也就不会出现指令重排的问题呀?
    Jooooooooo
        9
    Jooooooooo  
       2020-05-17 23:56:36 +08:00   ❤️ 1
    @dengsq 没看懂你说的问题是啥.

    "不加 volatile 时,不同线程之间的变量应该是不可见的" 这句不对. 只能说行为不定义, 可不可见取决于 cpu 的行为, 举个例子. 如果当时机器因为干别的活把当前核给让出做上下文切换了, 这个值就是可见的了

    更极端的例子, 你到一个单线程的机器上跑这个代码, 不会出现不可见的问题
    momocraft
        10
    momocraft  
       2020-05-18 00:02:43 +08:00   ❤️ 1
    保证可见的反面是 "不保证" 不是 "保证不"
    dengsq
        11
    dengsq  
    OP
       2020-05-18 00:23:04 +08:00
    @Jooooooooo @momocraft 结合二位的回答我就明白了,是我的理解有问题,取反取错了。
    非常感谢😄
    ArronJun
        12
    ArronJun  
       2020-05-19 08:10:43 +08:00 via iPhone
    打印方法加了同步关键字
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1375 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 38ms · UTC 17:40 · PVG 01:40 · LAX 10:40 · JFK 13:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.