图解 Volatile 原理三
你好呀,我是悟空呀~上篇我们讲到用 volatile 修饰的变量,当某线程更新变量后,其他线程也能感知到。那为什么其他线程能感知到变量更新?
其实这里就是用到了“窥探(snooping)”协议。在说“窥探(snooping)”协议之前,首先谈谈缓存一致性的问题。
缓存一致性
当多个 CPU 持有的缓存都来自同一个主内存的拷贝,当有其他 CPU 偷偷改了这个主内存数据后,其他 CPU 并不知道,那拷贝的内存将会和主内存不一致,这就是缓存不一致。那我们如何来保证缓存一致呢?这里就需要操作系统来共同制定一个同步规则来保证,而这个规则就有 MESI 协议。
如下图所示,CPU2 偷偷将 num 修改为 2,内存中 num 也被修改为 2,但是 CPU1 和 CPU3 并不知道 num 值变了。
MESI
当 CPU 写数据时,如果发现操作的变量是共享变量,即在其它 CPU 中也存在该变量的副本,系统会发出信号通知其它 CPU 将该内存变量的缓存行
设置为无效。如下图所示,CPU1 和 CPU3 中 num=1 已经失效了。
当其它 CPU 读取这个变量的时,发现自己缓存该变量的缓存行是无效的,那么它就会从内存中重新读取。
如下图所示,CPU1 和 CPU3 发现缓存的 num 值失效了,就重新从内存读取,num 值更新为 2。
总线嗅探
那其他 CPU 是怎么知道要将缓存更新为失效的呢?这里是用到了总线嗅探技术。
每个 CPU 不断嗅探总线上传播的数据来检查自己缓存值是否过期了,如果处理器发现自己的缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置为无效状态,当处理器对这个数据进行修改操作的时候,会重新从内存中把数据读取到处理器缓存中。
总线风暴
总线嗅探技术有哪些缺点?
由于 MESI 缓存一致性协议,需要不断对主线进行内存嗅探,大量的交互会导致总线带宽达到峰值。因此不要滥用 volatile,可以用锁来替代,看场景啦~
作者简介:悟空,8 年一线互联网开发和架构经验,用故事讲解分布式、架构设计、Java 核心技术。《JVM 性能优化实战》专栏作者,开源了《Spring Cloud 实战 PassJava》项目,公众号:悟空聊架构。本文已收录至 www.passjava.cn
版权声明: 本文为 InfoQ 作者【悟空聊架构】的原创文章。
原文链接:【http://xie.infoq.cn/article/374fb3d32f5881b73d01dc83f】。未经作者许可,禁止转载。
评论