• LDxy
    2019-07-22
    volatile关键字在用C语言编写嵌入式软件里面用得很多,不使用volatile关键字的代码比使用volatile关键字的代码效率要高一些,但就无法保证数据的一致性。volatile的本意是告诉编译器,此变量的值是易变的,每次读写该变量的值时务必从该变量的内存地址中读取或写入,不能为了效率使用对一个“临时”变量的读写来代替对该变量的直接读写。编译器看到了volatile关键字,就一定会生成内存访问指令,每次读写该变量就一定会执行内存访问指令直接读写该变量。若是没有volatile关键字,编译器为了效率,只会在循环开始前使用读内存指令将该变量读到寄存器中,之后在循环内都是用寄存器访问指令来操作这个“临时”变量,在循环结束后再使用内存写指令将这个寄存器中的“临时”变量写回内存。在这个过程中,如果内存中的这个变量被别的因素(其他线程、中断函数、信号处理函数、DMA控制器、其他硬件设备)所改变了,就产生数据不一致的问题。另外,寄存器访问指令的速度要比内存访问指令的速度快,这里说的内存也包括缓存,也就是说内存访问指令实际上也有可能访问的是缓存里的数据,但即便如此,还是不如访问寄存器快的。缓存对于编译器也是透明的,编译器使用内存读写指令时只会认为是在读写内存,内存和缓存间的数据同步由CPU保证。
    展开
     1
     45
  • 林三杠
    2019-07-22
    反复看了几次写回策略,才看明白。主要是“如果我们发现,我们要写入的数据所对应的 Cache Block 里,放的是别的内存地址的数据”这句。同一个cache地址可能被多个进程使用,使用前需要确认是否是自己的数据,是的话,直接写,不是自己的而且被标记为脏数据,需要同步回主内存。老师,我理解的对吧?
     3
     6
  • 曙光
    2019-10-22
    看了后面MESI协议的介绍,反而对本章示例程序有疑问,程序(2)中,虽然去掉了volatile的关键字,但ChangeListener应该接收到“写失效”的广播,然后中断忙等,再去内存获取最新数据。那有没有广播到ChangeListener的cpu cache呢? 本人i5-8250U, ChangeListener需要至少大于等于Thread.sleep(495)才能和程序(1)的测试结果一样,这是咋回事?
    
     3
  • WL
    2019-07-24
    请问老师在写回策略中检查Cache Block是不是别的内存地址的数据是啥意思, 一个cache block不是对应一个内存block吗?
     4
     2
  • 阿锋
    2019-07-22
    上面的流程图中,有一步是从主内存读取数据到cache block 我觉得这一步是多余的,因为下面接下来的一步是写入数据到cache block,之后都要写入新数据了,为啥还要读,不理解?
     4
     2
  • Knight²º¹⁸
    2019-12-20
    Java sleep 解释有问题,sleep 并不是说线程有时间去主内存中读取变量,而是 sleep 的线程会让出cpu,线程被唤醒后才会去重新加载变量。

    作者回复: Knight²º¹⁸同学,

    你好,你说的有道理,我去修改一下。

     2
     1
  • 随心而至
    2019-10-22
    比如,下面的程序,volatile变量count 每次都要写回到内存(Memory)中,而sum是线程栈的本地变量, 每次都只会写到线程栈中(可以对应CPU Cache)。所以最后add()/add2()方法的耗时,近似于Memory访问速度/CPU Cache访问速度。
    public class VolatilePerformanceTest {
        private static volatile int count =0;

        /**
         * count++注意并不是原子操作。
         */
        public static void add(){
            for(long i=0; i< 100000000; i++){
                count++;
            }
        }
        public static void add2(){
            int sum = 0;
            for(int i=0; i< 100000000; i++){
                sum++;
            }
        }

        public static void main(String[] args){
            long start =System.currentTimeMillis();
            //753 ms
            add();
            System.out.println(System.currentTimeMillis() - start);
            start= System.currentTimeMillis();
            //7ms
            add2();
            System.out.println(System.currentTimeMillis() - start);
        }
    }
    展开
    
     1
  • humor
    2019-07-22
    写回的内存写入策略的那张图中,为什么会有从主内存读取数据到cache block这一步呢?反正读入了主内存的数据也要被当前的数据覆盖掉的
     2
     1
  • 许先森
    2020-01-17
    总结写回:如果要写入的数据就在CPU高速缓存中,则直接覆盖,并标记为脏;如果不在,去找到对应的高速缓存块;找到之后,如果发现高速缓存块被标记脏,则把里面的数据“丢到”内中去,腾出位置,然后覆盖新数据进去,并且标记为脏;如果发现高速缓存块没有被标记为脏,则不管三七二十一,管你原来数据在内存有没有“备份”,我直接覆盖新数据进去,并且比较为脏。
    
    
  • 许先森
    2020-01-17
    文中有写:“写回策略的过程是这样的:如果发现我们要写入的数据,就在 CPU Cache 里面,那么我们就只是更新 CPU Cache 里面的数据。同时,我们会标记 CPU Cache 里的这个 Block 是脏(Dirty)的。所谓脏的,就是指这个时候,我们的 CPU Cache 里面的这个 Block 的数据,和主内存是不一致的。”
    所以图里的Cache Block指的是CPU高速缓存块,不是内存块。

    作者回复: 许先森同学,

    是的,这里指的是Cache,不是主内存。

    
    
  • Hash
    2019-12-23
    不加volatitle关键字

     private static int num = 1;
        public static void main(String[] args) {
            int[] arr = new int[8000000];
            for (int i = 0; i < 8000000; i++) {
                arr[i] = num;
                num++;
            }
    运行时间为:28毫秒

    加了关键字
    private static volatile int num = 1;
        public static void main(String[] args) {
            int[] arr = new int[8000000];
            for (int i = 0; i < 8000000; i++) {
                arr[i] = num;
                num++;
            }

    运行的时间为128毫秒
    展开

    作者回复: Hash同学,

    👍,加油,从实践中有所体会是最好的学习方法。

    
    
  • 花晨少年
    2019-12-15
    讲得好啊,透彻

    作者回复: 🙏 谢谢支持

    
    
  • 陈志恒
    2019-11-28
    1.这篇文章讨论的是单个线程数据一致性问题。(下一节,多个线程,或者是多个 CPU 核的缓存一致性的问题)
    2.知识点:volatile 关键字究竟代表什么含义呢?它会确保我们对于这个变量的读取和写入,都一定会同步到主内存里,而不是从 Cache 里面读取。
    
    
  • 追风筝的人
    2019-11-18
    volatile关键字会让数据都写入主内存,在多线程中一个线程的变量使用此关键字更改了变量之后,对其他线程这个改变可感知的。write through方式是无论缓存中有没有数据都更新到主内存。write back 是更新缓存,当需要把缓存中的脏数据交换出去时,数据时才会更新到主内存
    
    
  • 活的潇洒
    2019-08-21
    基础不牢、地洞山摇、我来补基础啦:
    day38 笔记:https://www.cnblogs.com/luoahong/p/11353749.html
     1
    
  • 💪😊
    2019-08-02
    volatile 会直接写内存吗?会不会直接写l3
    
    
  • WL
    2019-07-24
    请问老师这节课出现的cache block和上节课的内存 bolck是不是一个概念?
     1
    
  • 靠人品去赢
    2019-07-22
    老师你好,作类比的话,是不是Java主内存对应的是CPU的3级缓存。多个线程多个CPU最后在L3上读数据是一致性的?期待后面的缓存一致性的维护,会不会出行脏读脏写的情况。
    
    
  • humor
    2019-07-22
    老师好,JMM中的线程栈内存是对应到CPU Cache吗?以及JMM的主内存对应到硬件的主内存吗?JMM和cpu cpu cache 主内存之间的关系是相似的,还是就是同一个东西呢?
     1
    
  • 许童童
    2019-07-22
    程序没有写,我简答一下,如果不使用volatile关键字,相当于使用写直达,没有使用cpu cache。性能应该相差一个数量级。
     2
    
我们在线,来聊聊吧