V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Newyorkcity
V2EX  ›  问与答

我这样理解 Java 中 volatile 不能保证并发安全正确吗?

  •  
  •   Newyorkcity · 2020-08-24 23:41:53 +08:00 · 1188 次点击
    这是一个创建于 1535 天前的主题,其中的信息可能已经有所发展或是发生改变。
    public class VolatileDemo {
    
    	// volatile 变量
        private volatile static int count = 0;
    
        public static void main(String[] args) throws InterruptedException {
    
            Thread thread1 = new Thread(() -> {
                for (int i = 0; i < 1000; i++) {
                    count++;
                }
            });
            Thread thread2 = new Thread(() -> {
                for (int i = 0; i < 1000; i++) {
                    count++;
                }
            });
            thread1.start();
            thread2.start();
    
            thread1.join();
            thread2.join();
    
            System.out.println(count);
        }
    }
    

    以上是 volatile 不能保证并发安全的经典代码了,最终 count 结果不是 2000 。 count ++ 有三步,从主存读 count 到线程缓存,线程让 count + 1,线程写回 count 到主存

    volatile 保证了 线程让 count + 1,线程写回 count 到主存 这两个操作是原子的,但没有保证三个操作是原子的,所以导致

    thread1 读到 count

    thread2 读到 count

    thread2 让 count + 1

    thread2 写回 count

    thread1 让 count+1

    thead1 写回 count

    这种情况可能发生。而一旦发生的话,count 就少加了一次 1,所以最终结果不是 2000 。

    这样理解对吗?谢谢

    4 条回复    2021-01-13 16:31:57 +08:00
    tuzhis
        1
    tuzhis  
       2020-08-25 00:26:08 +08:00 via iPhone
    volatile 保证的是可见性,每次修改后必然读取到新的值,多线程情况下,假设原来是 1,同一时刻两个线程都读到了 1,那么加 1 后两个先后都去赋值 2,并不会变成 3 。可以去对比下 cas 的流程就会比较清晰,cas 中是发现值与一开始取值的不同,那么重新取值再计算
    vk42
        2
    vk42  
       2020-08-25 00:35:56 +08:00
    volatile 和原子性没有关系,如其字面意思它代表变量值可变(多线程只是一种场景,硬件相关代码也很常见)。lz 的问题随便找个原子操作和锁相关的教程就能搞懂了
    taogen
        3
    taogen  
       2020-08-25 00:36:06 +08:00 via Android
    并没有保证任何操作的原子性。只是保证可见性,一个线程每次读取时都去主内存去读,不会缓存到当前线程内存中,保证读取到最新值。
    保证原子性用 lock 。
    silencelixing
        4
    silencelixing  
       2021-01-13 16:31:57 +08:00
    volidate 保证的「可见性」,可以理解为「一个线程写,多个线程读」是安全的,多个线程能同时读取到正确的值。
    楼主的 case 里面,场景为「多个线程写,多个线程读」,所以不能保证线程安全
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5374 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 53ms · UTC 08:45 · PVG 16:45 · LAX 00:45 · JFK 03:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.