首先两个程序,证明cacheLine的存在。

public class ThreadTest {static volatile long[] arr = new long[2];public ThreadTest() {}public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {for(long i = 0L; i < 100000000L; arr[0] = i++) {}});Thread thread2 = new Thread(() -> {for(long i = 0L; i < 100000000L; arr[1] = i++) {}});long start = System.nanoTime();thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(System.nanoTime() - start);}
}
public class ThreadTest_1 {static volatile long[] arr = new long[16];public ThreadTest_1() {}public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {for(long i = 0L; i < 100000000L; arr[0] = i++) {}});Thread thread2 = new Thread(() -> {for(long i = 0L; i < 100000000L; arr[8] = i++) {}});long start = System.nanoTime();thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(System.nanoTime() - start);}
}

程序1,打印出的时间为
2278531100/ns
2330328000/ns
测试了五次,取出其中两次测试结果,不同的机器线程执行的时间肯定不一致,以自己机器为例。
程序2,打印出的时间为
556254500
344490100
显而易见,程序二的执行效率会比一的执行效率高很多,因为Intel的cpu的缓存行大小为64字节,程序二采用long数组,将两个值进行隔离,保证不再统一缓存行。
因为定义static变量的时候使用volatile,需要保证公共资源的可见性,程序1相对于程序二,每次在对变量在进行修改的时候根据缓存一致性协议(MESI),每次cpu在进行计算的时候都需要去主存中同步最新数据,所以时间耗时多。

扩展:对于缓存一致性协议,正常情况下,通过缓存锁实现一致性,对于无法缓存的数据或者是数据量过大的数据(缓存行一次无法全部加载),采用锁总线的方式保持一致性。

jdk1.7版本,其中一些源码,也是采用消除伪共享的代码方式,在jdk1.8中提供一个注解@Contended,对于高并发访问的常量,可以使用这个注解来保证变量不会跟其他变量加载在同一缓存行中,如果想要使用这个注解,需要添加JVM启动参数:-XX:-RestrictContended,解除对@Contended。
相应的测试代码:

public class ThreadTest_02 {@Contendedstatic volatile long arr1;@Contendedstatic volatile long arr2;public ThreadTest_02() {}public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {for(long i = 0L; i < 100000000L; arr1 = i++) {}});Thread thread2 = new Thread(() -> {for(long i = 0L; i < 100000000L; arr2 = i++) {}});long start = System.nanoTime();thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(System.nanoTime() - start);}
}

之所以jdk1.8提供这个注解,是为了在不同的电脑上(因为不是所有的cpu的缓存行都是64字节),有jvm编译成为机械码,在cpu计算的时候会始终保持变量不会跟其他并发量高的变量存于同一缓存行之内,更好的跨平台。
可以比较添加注解和注释注解两次的执行时间:
933722100(添加)
2569085400(注释)

最后在说明一下缓存行:
因为cpu的Registers处理速度为主存的100倍,对于想要处理的数据,不可能单次自读取这一个数字,为了使CPU的使用效率更可能高,和程序的局部性原理,cpu会将相邻的代码也会读取到内存中,interl的cpu是64字节。这就是所谓的缓存行。

cpu的缓存级别:l1,l2,l3;

个人感觉这个知识点可能会在面试的时候问的比较多,在正常业务逻辑中我们很少会使用@Contended,目前我的项目代码中是没有使用这个优化的,可能是并发并不是很高。如果本篇文章对大家有所帮助,关注一波,点赞一下,以后会将学习的内容,有意思的内容,卸载博客中,并且项目中遇到难搞的点也会卸载博客中,算是三省吾身。

关于intelCPU缓存行,以及伪共享问题相关推荐

  1. 读取缓存行的伪共享问题

    位于同一缓存行的两个不同数据,被两个不同的CPU锁定,产生相互影响,此即伪共享问题. 因为读取和写入都是以缓存行为基本单位,CPU1只需要X,却将位于同一缓存行中的Y给读取到了,CPU2只需要Y,却将 ...

  2. 从Java视角理解伪共享(False Sharing)

    从我的前一篇博文中, 我们知道了CPU缓存及缓存行的概念, 同时用一个例子说明了编写单线程Java代码时应该注意的问题. 下面我们讨论更为复杂, 而且更符合现实情况的多核编程时将会碰到的问题. 这些问 ...

  3. 多线程中的volatile和伪共享

      伪共享 false sharing,顾名思义,"伪共享"就是"其实不是共享".那什么是"共享"?多CPU同时访问同一块内存区域就是&qu ...

  4. @Contended / Disruptor 缓存行占满注解

    目录 缓存行与伪共享 Disruptor 缓存行填充 @Contended 速度测试 存储设备往往是速度越快价格越昂贵,速度越快价格越低廉.在计算机中,CPU 的速度远高于主存的速度,而主存的速度又远 ...

  5. 面试准备每日系列:计算机底层之并发编程(二)缓存行、一致性协议、伪共享、disruptor、CAS等待

    文章目录 1. 缓存行 Cache line 2. 缓存一致性协议 & 伪共享 3. 为什么不加volatile? 4. 编程先可用再调优 5. disruptor & CAS等待 1 ...

  6. 一篇对伪共享、缓存行填充和CPU缓存讲的很透彻的文章

    认识CPU Cache CPU Cache概述 随着CPU的频率不断提升,而内存的访问速度却没有质的突破,为了弥补访问内存的速度慢,充分发挥CPU的计算资源,提高CPU整体吞吐量,在CPU与内存之间引 ...

  7. 从缓存行出发理解volatile变量、伪共享False sharing、disruptor

    volatile关键字 当变量被某个线程A修改值之后,其它线程比如B若读取此变量的话,立刻可以看到原来线程A修改后的值 注:普通变量与volatile变量的区别是volatile的特殊规则保证了新值能 ...

  8. 伪共享和缓存行填充,Java并发编程还能这么优化!

    前言 关于伪共享的文章已经很多了,对于多线程编程来说,特别是多线程处理列表和数组的时候,要非常注意伪共享的问题.否则不仅无法发挥多线程的优势,还可能比单线程性能还差.随着JAVA版本的更新,再各个版本 ...

  9. java 缓存行填充_缓存伪共享问题以及解决方案缓存行填充

    缓存伪共享 共享对象存在同一个缓存中,由于MESI协议,一个对象中一些不需要改变的属性因为其他改变的属性,导致整个对象的缓存进入到M被修改状态. 目前的CPU是通常按照32或者64字节的缓存行(Cac ...

  10. CPU Cache下的伪共享和缓存行

    本文转载自https://blog.csdn.net/karamos/article/details/80126704 认识CPU Cache CPU Cache概述 随着CPU的频率不断提升,而内存 ...

最新文章

  1. 你了解计算机系统的层次结构吗?计算机语言怎么发展的?
  2. adb.exe: device offline
  3. Mysql总结(二)
  4. sql将html转成excel,使用SQL*PLUS,构建完美excel或html输出
  5. 信号量使用例子_用信号量锁定:一个例子
  6. arm-linux-gcc 硬浮点,ARMCC和GCC编译ARM代码的软浮点和硬浮点问题 【转】
  7. 那些月薪过万的程序员都是从什么时间开始的?
  8. application/x-www-form-urlencoded
  9. java 乱码 号处理器_java处理中日文字符串的乱码问题
  10. Mixly 二次开发 自定义库 OLED
  11. 对象存储、文件存储、块存储的区别和联系
  12. 情缘难舍 愿为一叶扁舟
  13. 大数据可视化设计师丹尼斯_自助数据可视化设计师如何谋生
  14. 笔记本外接显示器屏幕分辨率调节(亲测、实用)
  15. 从基础接口工具postman开始夯实软件测试基础(一)
  16. 例题5-3 安迪的第一个字典 UVa10815
  17. html 标题字体修改,如何更改HTML标题字体大小?
  18. 刷机命令android手机刷机后,wifi无法使用的解决方法
  19. C#中的ExecuteNonQuery();
  20. 采访 Paradigm合伙人 :Crypto将是席卷 世界 的强大 浪潮

热门文章

  1. 技术研究:DOOM3网络模型的演化与网络架构
  2. Android 项目中依赖项目、依赖库、依赖module中的jar包(第三方库)
  3. 如何开启Windows远程桌面服务
  4. 10 款新鲜出炉的jQuery UI插件
  5. 基于R统计分析——样本与分布
  6. python批量改变图像大小
  7. 麻省理工大学公开课笔记:算法导论(二)——课程简介及算法分析
  8. 碲化铋纳米线合成步骤
  9. 常与同好争高下,不与傻瓜论短长
  10. [洛谷P4118][Ynoi2016]炸脖龙I([洛谷P3934]Nephren Ruq Insania)