证明 volatile 不具备原子性

假设一个简单场景:多个线程同时操作一个共享数据

public class AtomicTest {
    public static volatile int count;

    public static void main(String[] args) {
        for (int i = 0; i < 500; i++) {
            new Thread(()->{
                AtomicTest.count++;
            }).start();
        }
        /** 主线程等所有线程执行完,再去读取变量,3秒足够 */
        ThreadUtils.threadSleep(3000);
        System.out.println(AtomicTest.count);
    }
}

多次运行后发现,结果基本都正确的理想值 500,因为每个线程运行的太快了。

但还是有可能会得到错误的值,放大这个可能性,修改:

// 让每个线程在操作数之前,都睡上10毫秒
ThreadUtils.threadSleep(10);

这样做的目的是,让多个线程都并行的效果

再运行,结构都是不同的错误值

其中,AtominTest.count++; 看起来只有一行代码,但它在字节码里可能需要多个指令来完成,在一个线程中的大致过程如下:

  1. 在方法去读取 count
  2. 压栈(每个线程都有它们独自的栈):把 count 压入栈顶
  3. 弹栈
  4. 加操作
  5. 把操作的结果值赋值给方法区的count

把这 5 个大致的操作看一个整体,当成原子性的操作,如果能保证多个线程遵循原子性的特性,那么结果是安全可靠的,

虽然volatile能保证 可见性 和 有序性,但它无法保证原子性,

每个线程都要执行上述的 5 个步骤,valatile 使得每个线程都在 主存中读写变量,并且按顺序执行操作步骤,但是多个线程一旦并行后,谁先做谁后做,就不能确定了
就是说,保证上述的原子性操作当前只有一个线程执行,完了后,再按序下一个线程来执行,synchronizedlock锁 不就是这么干的么🤔...

作者:Hong•Guo

出处:https://www.cnblogs.com/ghnb1/p/17326409.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Hong•Guo  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示