Java多线程学习笔记之二缓存
1、高速缓存
由来:处理器处理能力原因大于主内存(DRAM)访问速率,为了弥补这个差距,引入了高速缓存。
高速缓存是一种存取速率远比主内存大而容量远比主内存小的存储部件,每一个处理器都有其高速缓存。在引入高速缓存之后,处理器执行读、写操作时就不直接操作主内存,而是通过高速缓存执行的。变量名相当于内存地址,变量值相当于相应内存空间中存储的数据。可以理解为,高速缓存为程序中的数据做了一份对应主内存的副本,但高速缓存的存储容量是非常小的,这些数据并不会一直被高速缓存存储。高速缓存在内部结构相当于一个拉链散列表,包含若干个桶,每个桶又包含若干个缓存条目。
缓存条目分为三个部分:Tag、Data Block和Flag。Data Block也叫做缓存行,是高速缓存和主内存之间数据交换的最小单元,用于存储从内存中读取的或者准备写入内存的数据。Tag包含了与缓存行中数据相对应的内存地址的部分信息。Flag用于表示相应缓存行的状态。一个缓存行可以存若干个变量的值。

处理器在执行访问操作时会将相应的内存地址解码为tag、index和offest三部分。index相当于桶编号,用来定位内存地址对应的桶;tag通过与缓存条目的Tag进行比较,定位一个具体的缓存条目;一个缓存条目中存储多个变量,offest是缓存行内的位置偏移,可以定位一个变量在缓存行中存储的起始位置。根据内存地址的解码结果,在高速缓存中找到相应的数据,并且所在缓存条目的Flag表示是有效的,那么这个内存操作就称为缓存命中,否则,则称为缓存未命中。缓存未命中是,处理器会从主内存中加载并存入相应的缓存行中。
处理器一般都具有多个层次的高速缓存,一级缓存、二级缓存、三级缓存等。越靠近处理器的缓存,存取速率越快,容量越小。Linux系统可有通过lscpu查看高速缓存层次。如下图

2、缓存一致性协议
当多处理器操作共享变量时就会存在读脏数据和丢失更新的问题,为了解决这个问题,引入里缓存一致性协议。
MESI(Modified-Exclusive-Shared-Invalid)协议就是一种缓存一致性协议,它实现缓存一致性的思想类似于读写锁,对于同一地址的读操作是并发的,对于同一地址的写操作是独占的。通过一组状态和消息来实现这种控制。
MESI状态:
- Modified(更改过的,M):该状态表示相应缓存行对包含相应内存地址所做的更新结果数据。因为MESI协议中对写操作的地址是独占的,所以同一时刻,多个处理器上的高速缓存中Tag值相同的缓存条目中,只可能有一个缓存条目处于该状态,且该状态缓存条目的数据一定与主内存中数据不一致。
- Exclusive(独占的,E):该状态表示相应缓存行包含相应内存地址所对应的副本数据。该状态的缓存行独占了相应内存地址的副本数据,其余处理器中的高速缓存都将不再保留该数据的有效副本,且此时缓存行中的数据和主内存中包含的数据应该是一致的。
- Shared(共享的,S):该状态表示相应缓存行包含相应内存地址所对应的副本数据。如果一个缓存条目处于该状态,且其他处理器上也存在Tag值与该缓存条目Tag值相同的缓存条目,那么这些缓存条目也一定处于Shared状态。该状态下缓存行中包含的数据与主内存中的数据一致。
- Invalid(无效的,I):该状态表示相应缓存行中不包含任何内存地址对应的有效副本数据。该状态是缓存条目的初始状态。
MESI消息如下表:
| 消息名 | 消息类型 | 描述 |
| Read | 请求 | 通知其他处理器、主内存当前主内存准备读取某个数据。该消息包含待读取数据的内存地址。 |
| Read Response | 相应 | 该消息包含被请求读取的数据。该消息可能是主内存提供的,也可能是其他高速缓存提供的。 |
| Invalidate | 请求 | 通知其他处理器将其高速缓存中指定内存地址对应的缓存条目的状态设置为I,即删除相应内存地址的副本数据(更改其缓存条目的Flag值) |
| Invalidate Acknowledge | 相应 | 接收到Invalidate消息的处理器必须回复该消息,以表示删除了其高速缓存上相应的副本数据。 |
| Read Invalidate | 请求 | 该消息是又Read和Invalidate消息组合而成的,用于通知其他处理器当前处理器准备更新一个数据,并请求其他处理器删除其高速缓存中相应的副本数据。接收到该消息的处理器必须回复Read Response和Invalidate Acknowledge消息。 |
| Writeback | 请求 |
该消息包含要写入主内存的数据及其相应的内存地址。 |
假设多处理器要对A地址的B数据进行操作,B数据为共享变量。
读操作(简略):


写操作(简略):

3、硬件缓冲区:写缓冲器与无效化队列
MESI协议在解决缓存一致性问题的同时也引入了等待回复MESI消息的延迟问题,为了减少这种延迟,引入了写缓冲器和无效化队列。
写缓冲器:是处理器内部一个容量比高速缓存还要小的高速存储部件,每个处理器都有其写缓冲器,其内部可包含若干条目。一个处理器无法读取另一个处理器的写缓冲器上的内容。
处理器进行写操作时,若缓存条目状态为S,则将写操作相关数据写入写缓冲器中,并发送Invalidate消息。若缓存条目状态为I,则为写未命中,将写操作相关数据写入写缓冲器中,并发送Read Invalidate消息。这样,处理器在将操作相关数据写入写缓冲器就可以认为写操作已完成,即不需等待消息回复就可执行其他指令。而当处理器接收到其他处理器回复的针对同一套缓存条目的所有Invalidate Acknowledge时,会将写缓冲器中相应地址的写操作的结果写入相应的缓存行中,此时写操作相对于本处理器之外的其他处理器而言才算是完成。
无效化队列:处理器在接收到Invalidate消息后,并不删除消息中指定地址的副本数据,而是将消息存入无效化队列后就回复Invalidate Acknowledge消息,减少了写操作处理器的等待时间。
写缓冲器和无效化队列又会带来内存重排序和可见性问题。
Java多线程学习笔记之二缓存的更多相关文章
- Java多线程学习笔记(二)——Executor,Executors,ExecutorService比较
Executor:是Java线程池的超级接口:提供一个execute(Runnable command)方法;我们一般用它的继承接口ExecutorService. Executors:是java.u ...
- java 多线程学习笔记(二) -- IO密集型任务
IO密集型是指对IO操作较多的任务.下面以查询一些股票价格任务为例: YahooFinance.java public class YahooFinance { public static doubl ...
- Java多线程学习笔记(二)
三 多线程执行的共享数据和非共享数据: 共享数据:就是每个线程执行的时候共享数据使用,比如这个线程一个为5的数据,减少为4之后,另一个线程执行拿到的数据是4,两个线程执行的数据是共享的. 非共享数据: ...
- Java多线程学习笔记(一)——多线程实现和安全问题
1. 线程.进程.多线程: 进程是正在执行的程序,线程是进程中的代码执行,多线程就是在一个进程中有多个线程同时执行不同的任务,就像QQ,既可以开视频,又可以同时打字聊天. 2.线程的特点: 1.运行任 ...
- java多线程学习笔记——详细
一.线程类 1.新建状态(New):新创建了一个线程对象. 2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...
- JAVA多线程学习笔记(1)
JAVA多线程学习笔记(1) 由于笔者使用markdown格式书写,后续copy到blog可能存在格式不美观的问题,本文的.mk文件已经上传到个人的github,会进行同步更新.github传送门 一 ...
- Java NIO 学习笔记(二)----聚集和分散,通道到通道
目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...
- Java多线程学习笔记
进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...
- Java多线程学习笔记--生产消费者模式
实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...
随机推荐
- [转]SQL Server 2008 如何配置报表管理器
本文转自:https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008/cc281384%28v%3dsql.100%2 ...
- windows下使用python操作redis(Visual Studio Code)
1.编辑工具: Visual Studio Code(windows环境) 2.redis服务器:这里用了远程连接,需要配置redis.conf. (1)注释 #bind 127.0.0.1 (2)设 ...
- 【MongoDB-MongoVUE图像管理工具】
介绍一款很不错的开源的MongoDB图形化管理工具:MongoVUE . MongoVUE 1.6.9 破解版,下载地址.
- Mybatis的自动映射autoMappingBehavior与mapUnderscoreToCamelCase
autoMappingBehavior 在Mybatis的配置文件中添加settings属性的autoMappingBehavior <settings> <setting name ...
- Linux 安装redis,redis发布订阅,持久化
安装redis 1.安装redis的方式 -yum (删除这个yum安装的redis,我们只用源码编译安装的) -rpm -源码编译 2.删除原本的redis yum remove redis -y ...
- Hadoop HDFS 的 HttpFS
参考 Hadoop权威指南 第3章中3.4节 背景 要写一个操作HDFS的web后台(文件CRUD),虽然可以直接使用HDFS提供的FileSystem类然后通过get方法获取到一个Distribut ...
- python-中介者模式
源码地址:https://github.com/weilanhanf/PythonDesignPatterns 说明: 面向对象设计中鼓励将行为分不到各个对象中,这种分布可能会导致对象间有许多连接.最 ...
- linux学习笔记-目录结构(1)
每个linux系统的目录结构差不多,因为有FHS(Filesystem Hierarchy Standard)标准的规范. FHS的重点在于规范每个特定的目录下应该要放什么样的数据. FHS依据文件系 ...
- page、request、session和application有什么区别?
转自:http://liuyuru.iteye.com/blog/773367 1.简单说 page指当前页面.在一个jsp页面里有效 2.request 指从http请求到服务器处理结束,返回响应的 ...
- python 遇到的一些坑
lst = [1, 2, 4] print lst.__iter__().next() # 打印出来的是 1 print lst.__iter__().next() # 打印出来的是 1 # 调用__ ...