深入浅出计算机组成原理
徐文浩
bothub创始人
立即订阅
13019 人已学习
课程目录
已完结 62 讲
0/4登录后,你可以任选4讲全文学习。
入门篇 (5讲)
开篇词 | 为什么你需要学习计算机组成原理?
免费
01 | 冯·诺依曼体系结构:计算机组成的金字塔
02 | 给你一张知识地图,计算机组成原理应该这么学
03 | 通过你的CPU主频,我们来谈谈“性能”究竟是什么?
04 | 穿越功耗墙,我们该从哪些方面提升“性能”?
原理篇:指令和运算 (12讲)
05 | 计算机指令:让我们试试用纸带编程
06 | 指令跳转:原来if...else就是goto
07 | 函数调用:为什么会发生stack overflow?
08 | ELF和静态链接:为什么程序无法同时在Linux和Windows下运行?
09 | 程序装载:“640K内存”真的不够用么?
10 | 动态链接:程序内部的“共享单车”
11 | 二进制编码:“手持两把锟斤拷,口中疾呼烫烫烫”?
12 | 理解电路:从电报机到门电路,我们如何做到“千里传信”?
13 | 加法器:如何像搭乐高一样搭电路(上)?
14 | 乘法器:如何像搭乐高一样搭电路(下)?
15 | 浮点数和定点数(上):怎么用有限的Bit表示尽可能多的信息?
16 | 浮点数和定点数(下):深入理解浮点数到底有什么用?
原理篇:处理器 (18讲)
17 | 建立数据通路(上):指令+运算=CPU
18 | 建立数据通路(中):指令+运算=CPU
19 | 建立数据通路(下):指令+运算=CPU
20 | 面向流水线的指令设计(上):一心多用的现代CPU
21 | 面向流水线的指令设计(下):奔腾4是怎么失败的?
22 | 冒险和预测(一):hazard是“危”也是“机”
23 | 冒险和预测(二):流水线里的接力赛
24 | 冒险和预测(三):CPU里的“线程池”
25 | 冒险和预测(四):今天下雨了,明天还会下雨么?
26 | Superscalar和VLIW:如何让CPU的吞吐率超过1?
27 | SIMD:如何加速矩阵乘法?
28 | 异常和中断:程序出错了怎么办?
29 | CISC和RISC:为什么手机芯片都是ARM?
30 | GPU(上):为什么玩游戏需要使用GPU?
31 | GPU(下):为什么深度学习需要使用GPU?
32 | FPGA和ASIC:计算机体系结构的黄金时代
33 | 解读TPU:设计和拆解一块ASIC芯片
34 | 理解虚拟机:你在云上拿到的计算机是什么样的?
原理篇:存储与I/O系统 (17讲)
35 | 存储器层次结构全景:数据存储的大金字塔长什么样?
36 | 局部性原理:数据库性能跟不上,加个缓存就好了?
37 | 高速缓存(上):“4毫秒”究竟值多少钱?
38 | 高速缓存(下):你确定你的数据更新了么?
39 | MESI协议:如何让多核CPU的高速缓存保持一致?
40 | 理解内存(上):虚拟内存和内存保护是什么?
41 | 理解内存(下):解析TLB和内存保护
42 | 总线:计算机内部的高速公路
43 | 输入输出设备:我们并不是只能用灯泡显示“0”和“1”
44 | 理解IO_WAIT:I/O性能到底是怎么回事儿?
45 | 机械硬盘:Google早期用过的“黑科技”
46 | SSD硬盘(上):如何完成性能优化的KPI?
47 | SSD硬盘(下):如何完成性能优化的KPI?
48 | DMA:为什么Kafka这么快?
49 | 数据完整性(上):硬件坏了怎么办?
50 | 数据完整性(下):如何还原犯罪现场?
51 | 分布式计算:如果所有人的大脑都联网会怎样?
应用篇 (5讲)
52 | 设计大型DMP系统(上):MongoDB并不是什么灵丹妙药
53 | 设计大型DMP系统(下):SSD拯救了所有的DBA
54 | 理解Disruptor(上):带你体会CPU高速缓存的风驰电掣
55 | 理解Disruptor(下):不需要换挡和踩刹车的CPU,有多快?
结束语 | 知也无涯,愿你也享受发现的乐趣
免费
答疑与加餐 (5讲)
特别加餐 | 我在2019年F8大会的两日见闻录
FAQ第一期 | 学与不学,知识就在那里,不如就先学好了
用户故事 | 赵文海:怕什么真理无穷,进一寸有一寸的欢喜
FAQ第二期 | 世界上第一个编程语言是怎么来的?
特别加餐 | 我的一天怎么过?
深入浅出计算机组成原理
登录|注册

38 | 高速缓存(下):你确定你的数据更新了么?

徐文浩 2019-07-22
在我工作的十几年里,写了很多 Java 的程序。同时,我也面试过大量的 Java 工程师。对于一些表示自己深入了解和擅长多线程的同学,我经常会问这样一个面试题:“volatile 这个关键字有什么作用?”如果你或者你的朋友写过 Java 程序,不妨来一起试着回答一下这个问题。
就我面试过的工程师而言,即使是工作了多年的 Java 工程师,也很少有人能准确说出 volatile 这个关键字的含义。这里面最常见的理解错误有两个,一个是把 volatile 当成一种锁机制,认为给变量加上了 volatile,就好像是给函数加了 sychronized 关键字一样,不同的线程对于特定变量的访问会去加锁;另一个是把 volatile 当成一种原子化的操作机制,认为加了 volatile 之后,对于一个变量的自增的操作就会变成原子性的了。
// 一种错误的理解,是把volatile关键词,当成是一个锁,可以把long/double这样的数的操作自动加锁
private volatile long synchronizedValue = 0;
// 另一种错误的理解,是把volatile关键词,当成可以让整数自增的操作也变成原子性的
private volatile int atomicInt = 0;
amoticInt++;
事实上,这两种理解都是完全错误的。很多工程师容易把 volatile 关键字,当成和锁或者数据数据原子性相关的知识点。而实际上,volatile 关键字的最核心知识点,要关系到 Java 内存模型(JMM,Java Memory Model)上。
虽然 JMM 只是 Java 虚拟机这个进程级虚拟机里的一个内存模型,但是这个内存模型,和计算机组成里的 CPU、高速缓存和主内存组合在一起的硬件体系非常相似。理解了 JMM,可以让你很容易理解计算机组成里 CPU、高速缓存和主内存之间的关系。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入浅出计算机组成原理》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(18)

  • LDxy
    volatile关键字在用C语言编写嵌入式软件里面用得很多,不使用volatile关键字的代码比使用volatile关键字的代码效率要高一些,但就无法保证数据的一致性。volatile的本意是告诉编译器,此变量的值是易变的,每次读写该变量的值时务必从该变量的内存地址中读取或写入,不能为了效率使用对一个“临时”变量的读写来代替对该变量的直接读写。编译器看到了volatile关键字,就一定会生成内存访问指令,每次读写该变量就一定会执行内存访问指令直接读写该变量。若是没有volatile关键字,编译器为了效率,只会在循环开始前使用读内存指令将该变量读到寄存器中,之后在循环内都是用寄存器访问指令来操作这个“临时”变量,在循环结束后再使用内存写指令将这个寄存器中的“临时”变量写回内存。在这个过程中,如果内存中的这个变量被别的因素(其他线程、中断函数、信号处理函数、DMA控制器、其他硬件设备)所改变了,就产生数据不一致的问题。另外,寄存器访问指令的速度要比内存访问指令的速度快,这里说的内存也包括缓存,也就是说内存访问指令实际上也有可能访问的是缓存里的数据,但即便如此,还是不如访问寄存器快的。缓存对于编译器也是透明的,编译器使用内存读写指令时只会认为是在读写内存,内存和缓存间的数据同步由CPU保证。
    2019-07-22
    1
    38
  • 林三杠
    反复看了几次写回策略,才看明白。主要是“如果我们发现,我们要写入的数据所对应的 Cache Block 里,放的是别的内存地址的数据”这句。同一个cache地址可能被多个进程使用,使用前需要确认是否是自己的数据,是的话,直接写,不是自己的而且被标记为脏数据,需要同步回主内存。老师,我理解的对吧?
    2019-07-22
    1
    5
  • 曙光
    看了后面MESI协议的介绍,反而对本章示例程序有疑问,程序(2)中,虽然去掉了volatile的关键字,但ChangeListener应该接收到“写失效”的广播,然后中断忙等,再去内存获取最新数据。那有没有广播到ChangeListener的cpu cache呢? 本人i5-8250U, ChangeListener需要至少大于等于Thread.sleep(495)才能和程序(1)的测试结果一样,这是咋回事?
    2019-10-22
    2
  • WL
    请问老师在写回策略中检查Cache Block是不是别的内存地址的数据是啥意思, 一个cache block不是对应一个内存block吗?
    2019-07-24
    2
    2
  • 阿锋
    上面的流程图中,有一步是从主内存读取数据到cache block 我觉得这一步是多余的,因为下面接下来的一步是写入数据到cache block,之后都要写入新数据了,为啥还要读,不理解?
    2019-07-22
    2
    1
  • humor
    写回的内存写入策略的那张图中,为什么会有从主内存读取数据到cache block这一步呢?反正读入了主内存的数据也要被当前的数据覆盖掉的
    2019-07-22
    1
    1
  • 陈志恒
    1.这篇文章讨论的是单个线程数据一致性问题。(下一节,多个线程,或者是多个 CPU 核的缓存一致性的问题)
    2.知识点:volatile 关键字究竟代表什么含义呢?它会确保我们对于这个变量的读取和写入,都一定会同步到主内存里,而不是从 Cache 里面读取。
    2019-11-28
  • 追风筝的人
    volatile关键字会让数据都写入主内存,在多线程中一个线程的变量使用此关键字更改了变量之后,对其他线程这个改变可感知的。write through方式是无论缓存中有没有数据都更新到主内存。write back 是更新缓存,当需要把缓存中的脏数据交换出去时,数据时才会更新到主内存
    2019-11-18
  • 随心而至
    比如,下面的程序,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);
        }
    }
    2019-10-22
  • 活的潇洒
    基础不牢、地洞山摇、我来补基础啦:
    day38 笔记:https://www.cnblogs.com/luoahong/p/11353749.html
    2019-08-21
  • 💪😊
    volatile 会直接写内存吗?会不会直接写l3
    2019-08-02
  • WL
    请问老师这节课出现的cache block和上节课的内存 bolck是不是一个概念?
    2019-07-24
  • 靠人品去赢
    老师你好,作类比的话,是不是Java主内存对应的是CPU的3级缓存。多个线程多个CPU最后在L3上读数据是一致性的?期待后面的缓存一致性的维护,会不会出行脏读脏写的情况。
    2019-07-22
  • humor
    老师好,JMM中的线程栈内存是对应到CPU Cache吗?以及JMM的主内存对应到硬件的主内存吗?JMM和cpu cpu cache 主内存之间的关系是相似的,还是就是同一个东西呢?
    2019-07-22
  • 许童童
    程序没有写,我简答一下,如果不使用volatile关键字,相当于使用写直达,没有使用cpu cache。性能应该相差一个数量级。
    2019-07-22
    2
  • 斐波那契
    在jdk5之前由于java的乱序执行导致volatile关键字还是有可能不可见的 后来引入了happen-before规则 才让volatile具有可见性 但是volatile并不具有原子性 也就是跟管程(synchronized)还是有区别的
    2019-07-22
  • d
    这个缓存模型只适用于Java吗,其他语音呢,老师可否引申一下
    2019-07-22
  • -W.LI-
    老师好!写回的优势是多次局部命中的时候可以打包写回减少开销是么?
    2019-07-22
收起评论
18
返回
顶部