FalseSharing-伪共享
1.CPU缓存
要了解什么是伪共享,首先得了解CPU缓存架构与缓存行的知识
(1)<CPU缓存架构>
主内存RAM是数据存在的地方,CPU和主内存之间有好几级缓存,因为即使直接访问主内存相对来说也是非常慢的。如果对一块数据做相同的运算多次,那么在执行运算的时候把它加载到离CPU很近的地方就有意义了,避免每次都到主内存中去取这个数据。

越靠近CPU的缓存越快也越小,所以L1缓存很小但很快,并且紧靠着在使用它的CPU内核。
L2大一些,但也慢一些,并且仍然只能被一个单独的CPU核使用。
L3在现代多核机器中更普遍,仍然更大,更慢,并且被单个插槽上的所有CPU核共享。
最后,主内存保存着程序运行的所有数据,它更大,更慢,由全部插槽上的所有CPU核共享。

当CPU执行运算的时候,它先去L1查找所需的数据,再去L2,然后L3,最后如果这些缓存中都没有,所需的数据就要去主内存拿。
走得越远,运算耗费的时间就越长。所以如果进行一些很频繁的运算,要确保数据在L1缓存中。
(2)<CPU缓存行>
缓存失效其实指缓存行失效,Cache是由很多个Cache line 组成的,每个缓存行大小是32~128字节(通常是64字节)。我们这里假设缓存行是64字节,而java的一个Long类型是8字节,这样的话一个缓存行就可以存8个Long类型的变量,如下图所示。CPU 每次从主内存中获取数据的时候都会将相邻的数据存入到同一个缓存行中。假设我们访问一个Long内存对应的数组的时候,如果其中一个被加载到内存中,那么对应的后面的7个数据也会被加载到对应的缓存行中,这样就会非常快的访问数据。

2.伪共享
根据MESI协议(缓存一致性协议),我们知道在一个缓存中的数据变化的时候会将其他所有存储该缓存的缓存(其实是缓存行)都失效。
(1)<示例概述>
下图中显示的是一个槽的情况:里面是多个CPU, 如果CPU1上面的线程更新了变量X,根据MESI协议,那么变量X对应的所有缓存行都会失效(由于X和Y被放到了一个缓存行,所以一起失效了),这个时候如果cpu2中的线程进行读取变量Y,发现缓存行失效,想获取Y就会按照缓存查找策略,往上查找。如果期间cpu1对应的线程更新X后没有访问X(也就是没有刷新缓存行),cpu2的线程就只能从主内存中获取数据,对性能就会造成很大的影响,这就是伪共享。
表面上 X 和 Y 都是被独立线程操作的,而且两操作之间也没有任何关系。只不过它们共享了一个缓存行,但所有竞争冲突都是来源于共享。

(2)<解决方法>
这个问题的解决办法有两个:
1.使用对齐填充,因为一个缓存行大小是64个字节,如果读取的目标数据小于64个字节,可以增加一些无意义的成员变量来填充。
2.在Java8里面,提供了@Contented注解,它也是通过缓存行填充来解决伪共享问题的,被@Contented注解声明的类或者字段,会被加载到独立的缓存行上。
FalseSharing-伪共享的更多相关文章
- 伪共享 FalseSharing (CacheLine,MESI) 浅析以及Java里的解决方案
起因 在阅读百度的发号器 uid-generator 源码的过程中,发现了一段很奇怪的代码: /** * Represents a padded {@link AtomicLong} to preve ...
- 多线程伪共享FalseSharing
1. 伪共享产生: 在SMP架构的系统中,每个CPU核心都有自己的cache,当多个线程在不同的核心上,并且某线程修改了在同一个cache line中的数据时,由于cache一致性原则,其他核心cac ...
- 伪共享(false sharing),并发编程无声的性能杀手
在并发编程过程中,我们大部分的焦点都放在如何控制共享变量的访问控制上(代码层面),但是很少人会关注系统硬件及 JVM 底层相关的影响因素.前段时间学习了一个牛X的高性能异步处理框架 Disruptor ...
- Java8的伪共享和缓存行填充--@Contended注释
在我的前一篇文章<伪共享和缓存行填充,从Java 6, Java 7 到Java 8>中, 我们演示了在Java 8中,可以采用@Contended在类级别上的注释,来进行缓存行填充.这样 ...
- 伪共享和缓存行填充,从Java 6, Java 7 到Java 8
关于伪共享的文章已经很多了,对于多线程编程来说,特别是多线程处理列表和数组的时候,要非常注意伪共享的问题.否则不仅无法发挥多线程的优势,还可能比单线程性能还差.随着JAVA版本的更新,再各个版本上减少 ...
- java 伪共享
MESI协议及RFO请求典型的CPU微架构有3级缓存, 每个核都有自己私有的L1, L2缓存. 那么多线程编程时, 另外一个核的线程想要访问当前核内L1, L2 缓存行的数据, 该怎么办呢?有人说可以 ...
- java中伪共享问题
伪共享(False Sharing) 原文地址:http://ifeve.com/false-sharing/ 作者:Martin Thompson 译者:丁一 缓存系统中是以缓存行(cache l ...
- 并发性能的隐形杀手之伪共享(false sharing)
在并发编程过程中,我们大部分的焦点都放在如何控制共享变量的访问控制上(代码层面),但是很少人会关注系统硬件及 JVM 底层相关的影响因素.前段时间学习了一个牛X的高性能异步处理框架 Disruptor ...
- Java 中的伪共享详解及解决方案
1. 什么是伪共享 CPU 缓存系统中是以缓存行(cache line)为单位存储的.目前主流的 CPU Cache 的 Cache Line 大小都是 64 Bytes.在多线程情况下,如果需要修改 ...
- 伪共享(False Sharing)
原文地址:http://ifeve.com/false-sharing/ 作者:Martin Thompson 译者:丁一 缓存系统中是以缓存行(cache line)为单位存储的.缓存行是2的整数 ...
随机推荐
- .net core -利用 BsonDocumentProjectionDefinition 和Lookup 进行 join 关联 MongoDB 查询
前序 前段时间由于项目需要用到MongoDB,但是MongoDB不建议Collection join 查询,网上很多例子查询都是基于linq 进行关联查询.但是在stackoverflow找到一个例 ...
- go-zero docker-compose 搭建课件服务(九):http统一返回和集成日志服务
0.索引 go-zero docker-compose 搭建课件服务(九):http统一返回和集成日志服务 0.1源码地址 https://github.com/liuyuede123/go-zero ...
- Android 13 新特性及适配指南
Android 13(API 33)于 2022年8月15日 正式发布(发布时间较往年早了一些),正式版Release源代码也于当日被推送到AOSP Android开源项目. 截止到笔者撰写这篇文章时 ...
- python tcp select 多路复用
1 #!/usr/bin/python 2 # -*- coding: UTF-8 -*- 3 # 文件名:tcpserver.py 4 5 import socket 6 import time 7 ...
- 我的Vue之旅 09 数据数据库表的存储与获取实现 Mysql + Golang
第四期 · 将部分数据存储至Mysql,使用axios通过golang搭建的http服务器获取数据. 新建数据库 DROP DATABASE VUE; create database if not e ...
- python 类相关 下划线相关 __init__
类 1.静态方法 class C(object): @staticmethod def f(): print('runoob'); C.f(); # 静态方法无需实例化 cobj = C() cobj ...
- TKK: 更新 TKK 失败,请检查网络连接 idea翻译错误-IDEA翻译失败-Translation用不了
IDEA 提示:更新 TKK 失败,请检查网络连接 解决方法: 1.进入 C:\Windows\System32\drivers\etc 找到 hosts文件修改 注意:如果用记事本打开不能修改,则修 ...
- 2022春每日一题:Day 37
题目:[USACO14FEB]Auto-complete S 字典树套路题,字典树优化剪枝,加个cnt标记即可 代码: #include <cstdio> #include <cst ...
- TortoiseGit间接处理linux目录下的仓库,用到window映射linux目录方案
原始需求 习惯用TortoiseGit查看git仓库信息和历史日志,但这个工具只支持window,我希望linux也能用 虽然有其他linux的GUI的git工具,但我用到的linux基本都是无界面版 ...
- Training: MySQL I
原题链接:http://www.wechall.net/challenge/training/mysql/auth_bypass1/index.php 题目告诉我们这是一个经典的mysql注入挑战,我 ...