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多线程学习笔记之二缓存的更多相关文章

  1. Java多线程学习笔记(二)——Executor,Executors,ExecutorService比较

    Executor:是Java线程池的超级接口:提供一个execute(Runnable command)方法;我们一般用它的继承接口ExecutorService. Executors:是java.u ...

  2. java 多线程学习笔记(二) -- IO密集型任务

    IO密集型是指对IO操作较多的任务.下面以查询一些股票价格任务为例: YahooFinance.java public class YahooFinance { public static doubl ...

  3. Java多线程学习笔记(二)

    三 多线程执行的共享数据和非共享数据: 共享数据:就是每个线程执行的时候共享数据使用,比如这个线程一个为5的数据,减少为4之后,另一个线程执行拿到的数据是4,两个线程执行的数据是共享的. 非共享数据: ...

  4. Java多线程学习笔记(一)——多线程实现和安全问题

    1. 线程.进程.多线程: 进程是正在执行的程序,线程是进程中的代码执行,多线程就是在一个进程中有多个线程同时执行不同的任务,就像QQ,既可以开视频,又可以同时打字聊天. 2.线程的特点: 1.运行任 ...

  5. java多线程学习笔记——详细

    一.线程类  1.新建状态(New):新创建了一个线程对象.        2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...

  6. JAVA多线程学习笔记(1)

    JAVA多线程学习笔记(1) 由于笔者使用markdown格式书写,后续copy到blog可能存在格式不美观的问题,本文的.mk文件已经上传到个人的github,会进行同步更新.github传送门 一 ...

  7. Java NIO 学习笔记(二)----聚集和分散,通道到通道

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  8. Java多线程学习笔记

    进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...

  9. Java多线程学习笔记--生产消费者模式

    实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...

随机推荐

  1. UVa 1572 Self-Assembly (拓扑排序)

    题目链接: https://cn.vjudge.net/problem/UVA-1572 Automatic Chemical Manufacturing is experimenting with ...

  2. 深入出不来nodejs源码-V8引擎初探

    原本打算是把node源码看得差不多了再去深入V8的,但是这两者基本上没办法分开讲. 与express是基于node的封装不同,node是基于V8的一个应用,源码内容已经渗透到V8层面,因此这章简述一下 ...

  3. OAuth2.0的理解&基础

    此文章是复制黏贴网上文章的,主要做自己备用着看(也加了自己的一点见解),喜欢的读者也可以看. OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2 ...

  4. ASP.NET开发,从二层至三层,至面向对象 (2)

    继续上一篇<ASP.NET开发,从二层至三层,至面向对象>http://www.cnblogs.com/insus/p/3822624.html .我们了解到怎样把自己的程序由二层变为三层 ...

  5. 微软宣布.NET开发环境将开源 支持三大操作系统(windows,Mac OS X和Linux)(转)

    微软周三(11月12日)公布了.NET开发框架开源计划.公司拟将这长期以来只能运行于Windows系统下的开发环境,通过GitHub开源,以实现跨平台支持Mac OS X和Linux.根据微软公布的计 ...

  6. [android] 帧动画和补间动画

    逐帧显示一张图片,连起来成为动画 在res/drawable/目录下,创建一个xxx.xml的文件 添加<animation-list>节点,设置是否循环android:oneshot:” ...

  7. Java - TreeMap源码解析 + 红黑树

    Java提高篇(二七)-----TreeMap TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap ...

  8. 在IDEA里创建web项目,以及web 项目部署

    在IDEA里创建web项目很简单: 1).先创建一个简单的maven项目,这个步骤我就不说了. 2).maven项目创建完后,因为我们需要的是web项目,因此我们要在pom.xml文件里设置packa ...

  9. mysql count(*) vs count(1)

    perfer count(*) 官方文档: _InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way ...

  10. JPA、ORM

    JPA:全称:Java Persistence API 解释:Java持久层API (接口规范) ORM映射元数据 JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系 ...