2.java并发机制及实现原理(1)
2019-08-25 本文已影响0人
农民工进城
在多线程中synchronized和volatile扮演者重要的角色,volatile是轻量级的,它保证了共享变量的可见性,即当一个线程修改带有volatile修饰的变量时,其他线程能够读到修改的之后的值。
本章要点
1.一致性协议
2.volatile
2.1一致性协议
CPU一致性协议是MESI协议,MWSI分别是指Cache line的4个状态: (Modified(修改) 、Exclusive(互斥、排他) Shared(共享)、Invalid(无效)。
状态 | 描述 |
---|---|
M: 被修改(Modified) | 缓存行只被缓存在该CPU的缓存中,并且是被修改过的(dirty),即与主存中的数据不一致 |
E: 独享的(Exclusive) | 缓存行只被缓存在该CPU的缓存中,它是未被修改过的(clean),与主存中数据一致。 |
S: 共享的(Shared) | 缓存行被多个CPU缓存,并且各个缓存中的数据与主存数据一致(clean),当有一个CPU修改该缓存行中,其它CPU中该缓存行可以被作废(变成无效状态(Invalid)) |
I: 无效的(Invalid) | 该缓存是无效的(可能有其它CPU修改了该缓存行) |
MESI协议:以总线为互连机构的多处理器系统。各cache控制器除负责响应自己CPU的内存读写操作(包括读/写命中与未命中)外,还要负责监听总线上的其它CPU的内存读写活动(包括读监听命中与写监听命中)并对自己的cache予以相应处理。所有这些处理过程要维护cache一致性,必须符合MESI协议状态转换规则。
CPU的几个术语:
术语 | 单词 | 描述 |
---|---|---|
缓存行 | cache line | CPU缓存的最小存储单位 |
内存屏障 | memory barriers | 一组处理器指令,用于对内存操作顺序对限制 |
原子操作 | atomic operations | 操作不再进行可分割 |
缓冲行填充 | cache line fill | 当处理器识别到从内存读取对数据是可缓存的,就会将数据放到适当的缓存行中 |
缓冲命中 | cache line fill | 当处理器识别到从内存读取对数据是可缓存的,就会将数据放到适当的缓存行中 |
缓冲行填充 | cache hit | 处理器识别到缓存是数据没发生改变,则从缓存行中读取数据 |
写命中 | write hit | 当处理器将操作数写回到一个内存缓存的区域时,它首先会检查这个缓存的内存地址是否在缓存行中,如果存在一个有效的缓存行,则处理器将这个操作数写回到缓存,而不是写回内存,这个操作被称为写命中 |
写缺失 | write misses the cache | 一个有效的缓存行被写入到不存在的内存区域 |
那么在多个CPU下是如何保证数据一致性呢?
每个CPU通过嗅探在总线上传播的数据来检查自己的缓存是否过期,当处理器发现自己的缓存行对应的内存地址被修改(Modified),则就会将当前处理器的缓存设置成无效状态(Invalid),当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读取到处理器缓存中。
2.2 volatile关键字
如果某个字段volatile修饰时,如果对该变量进行写操作时会发生两件事:
- 1)将当前处理器缓存行的数据写回到系统内存中
- 2)这个回写操作会使其他CPU缓存的该变量数据的内存地址无效
所以当其他线程进行读取操作的时候会刷新缓存,达到数据一致性或可见行的效果。
volatile只保证可见性,不能保证原子性;volatile 禁止指令重排序
系统缓存相关知识:
为了提高处理速度,处理器不直接和内存进行通信,而是现将系统内存的数据读取到内部缓存中(L1,L2,L3等)后在进行操作。当进行读取操作的时候,CPU会先在最快的L1中寻找需要的数据,找不到再去找次快的L2,还找不到再去找L3,L3都没有那就只能去内存找了。
名称 | 速度 | 容量 | CPU距离 |
---|---|---|---|
L1缓存 | 最快 | 最小 | 最近 |
L2缓存 | 较快 | 最小 | 较近 |
L3缓存 | 较慢 | 最大 | 较远 |
追加字节,填满缓存行(一般是64字节),避免伪共享,可优化volatile