引入高速缓存概念
- 在计算机在执行程序时,以指令为单位来执行 , 每条指令都是在CPU中执行的,而执行指令过程中 , 势必涉及到数据的读取和写入 。
- 由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行指令的速度很快 , 而从内存读取数据和向内存写入数据的过程相对很慢 , 因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度 。因此就引入了高速缓存 。
- 特性:缓存(Cache memory)是硬盘控制器上的一块内存,是硬盘内部存储和外界接口之间的缓冲器 。
- 预读取
?相当于提前加载,猜测你可能会用到硬盘相邻存储地址的数据,它会提前进行加载到缓存中,后面你需要时,CPU就不需要去硬盘读取数据,直接读取缓存中的数据传输到内存中就OK了 , 由于读取缓存的速度远远高于读取硬盘时磁头读写的速度 , 所以能够明显的改善性能 。
- 对写入动作进行缓存
?硬盘接到写入数据的指令之后,并不会马上将数据写入到盘片上,而是先暂时存储在缓存里,然后发送一个“数据已写入”的信号给系统 , 这时系统就会认为数据已经写入,并继续执行下面的工作,而硬盘则在空闲(不进行读取或写入的时候)时再将缓存中的数据写入到盘片上 。
- 换到应用程序层面也就是,当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据同步到主存当中 。
【从缓存入门到并发编程三要素详解 Java中 volatile 、final 等关键字解析案例】
i = i + 1;
- 当线程执行这个语句时,会先从主存当中读取i的值,然后复制一份到高速缓存当中,然后CPU执行指令对i进行加1操作,然后将数据写入高速缓存 , 最后将高速缓存中i最新的值刷新到主存当中 。
- 这个代码在单线程中运行是没有任何问题的,但是在多线程中运行就会有问题了(存在临界区) 。在多核CPU中,每条线程可能运行于不同的CPU中,因此每个线程运行时有自己的高速缓存区(对单核CPU来说,其实也会出现这种问题 , 只不过是以线程调度的形式来分别执行的) 。
- 线程一执行
i = i + 1
,线程二执行var = i
- 线程二此时去主存中获取变量
i
,线程一只是在高速缓存中更新了变量,还未将变量i
写会主存 - 线程二读到的
i
不是最新值,此时多线程导致数据不一致
?这里的共享又可以回到上文中,即为上面所说,他们每个线程都有自己的高速缓存区,但是都是从同一个主存同步获取变量 。
那么这种问题应该怎样解决呢?
解决缓存不一致问题(硬件层面)
- 总线加锁模式
- 由于CPU在执行命令和其他组件进行通信的时候都需要通过总线,倘若对总线加锁的话,线程一执行
i = i + 1
整个命令过程中,其他线程是无法访问主存的 。 - 优缺只有一个,可以解决本问题;缺点的话除了优点全是缺点,效率低,成本高·····(谁也不会让一个主存同时只能干一件事)
- 由于CPU在执行命令和其他组件进行通信的时候都需要通过总线,倘若对总线加锁的话,线程一执行
- 缓存一致性协议
- 协议可以保证每个缓存中使用的共享变量的副本是一致的 , 原理:CPU对主存中的共享变量有写入操作时,会立即通知其他CPU将该变量缓存行置为无效状态 。其他CPU发现该变为无效状态时,就会重新去主存中读取该变量最新值 。
- 优点就是可以解决问题,读多写少效率还OK;缺点就是实现繁琐,较耗费性能,在对于写多的场景下效率很不可观
?答:共享资源不能及时同步更新,归根于 分时系统上下文切换时 指令还未执行完毕 (没有写回结果) 更新异常
引入并解释并发编程特性?众所周知现在的互联网大型项目 , 都是采用分布式架构同时具有其“三高症状” , 高并发、高可用、高性能 。高并发为其中最重要的特性之一,在高并发场景下并发编程就显得尤为重要,其并发编程的特性为原子性、可见性、有序性 。
推荐阅读
- [CG从零开始] 4. pyopengl 绘制一个正方形
- 一文读懂Apache Geode缓存中间件
- 跳棋怎么玩(跳棋怎么玩新手入门)
- 跳跳棋怎么玩(跳棋怎么玩新手入门)
- [CG从零开始] 3. 安装 pyassimp 库加载模型文件
- 塔罗牌该怎样入门(塔罗入门禁忌)
- 网购的兔子怎么养(从小摊买的兔子怎么养)
- 企业运维 | MySQL关系型数据库在Docker与Kubernetes容器环境中快速搭建部署主从实践
- 如何0到1构建DevOps?
- 小米11Ultra发热严重_小米11Ultra发热严重官方回应