Java8引入了@Contented这个新的注解来减少伪共享(False Sharing)的发生。本文介绍了@Contented注解并解释了为什么False Sharing是如何影响性能的。

缓存行

CPU读取内存数据时并非一次只读一个字节,而是会读一段64字节长度的连续的内存块(chunks of memory),这些块我们称之为缓存行(Cache line)。

假设你有两个线程(Thread1和Thread2)都会修改同一个volatile变量x:

1

volatile long x;

如果Thread1先改变x的值,然后Thread2又去读它:

1

2

Thread 1: x= 3;

Thread 2: System.out.print(x);

那么x所在缓存行上的所有64个字节的值都要被重新加载,因为CPU核心间交换数据是以缓存行为最小单位的。当然Thread1和Thread2是有可能在同一个核心上运行的,但我们此处假设两个线程在不同的核心上运行。

已知long类型占8个字节,缓存行长度为64个字节,那么一个缓存行可以保存8个long型变量,我们已经有了一个long型的x,假设x所在缓存行里还有其他7个long型变量,v1到v7:

1

x, v1, v2, v3, v4, v5 , v6 , v7

伪共享(False Sharing)

这个缓存行可以被许多线程访问。如果其中一个修改了v2,那么会导致Thread1和Thread2都会重新加载整个缓存行。你可能会疑惑为什么修改了v2会导致Thread1和Thread2重新加载该缓存行,毕竟只是修改了v2的值啊。虽然说这些修改逻辑上是互相独立的,但同一缓存行上的数据是统一维护的,一致性的粒度并非体现在单个元素上。这种不必要的数据共享就称之为“伪共享”(False Sharing)。

填充(Padding)

一个CPU核心在加载一个缓存行时要执行上百条指令。如果一个核心要等待另外一个核心来重新加载缓存行,那么他就必须等在那里,称之为stall(停止运转)。减少伪共享也就意味着减少了stall的发生,其中一个手段就是通过填充(Padding)数据的形式,来保证本应有可能位于同一个缓存行的两个变量,在被多线程访问时必定位于不同的缓存行。

在下面这个例子里,我们试图通过填充的方式,使得xv1位于不同的缓存行:

1

2

3

4

5

6

7

8

9

10

11

public class FalseSharingWithPadding {

public volatile long x;

public volatile long p2; // padding

public volatile long p3; // padding

public volatile long p4; // padding

public volatile long p5; // padding

public volatile long p6; // padding

public volatile long p7; // padding

public volatile long p8; // padding

public volatile long v1;

}

在你考虑使用填充之前,必须要了解的一点是JVM可能会清除无用字段或重排无用字段的位置,这样的话,可能无形中又会引入伪共享。我们也没有办法指定对象在堆内驻留的位置。

为了避免无用字段被消除,通常我们会用volatile修饰一下。个人建议只需为处于激烈竞争状态的类进行填充处理,而且一般只有通过对其性能分析才能发现性能上的不同。通常在性能分析时,最好在对其迭代访问10000次之后再去采样,这样可以消除JVM本身的运行时优化策略带来的影响。

Java8和@Contended

除了对字段进行填充之外,还有一个比较清爽的方法,那就是对需要避免陷入伪共享的字段进行注解,这个注解暗示JVM应当将字段放入不同的缓存行,这也正是JEP142的相关内容。

该JEP引入了@Contented注解。被这个注解修饰的字段应当和其他的字段驻留在不同的位置。

1

2

3

4

5

public class Point {

int x;

@Contended

int y;

}

上面的代码将x和y置于不同的缓存行。@Contented注解将y移动到远离对象头部的地方,(以避免和x一起被加载到同一个缓存行)。

参考

http://openjdk.java.net/projects/jdk8/features
http://beautynbits.blogspot.co.uk/2012/11/the-end-for-false-sharing-in-java.html
http://openjdk.java.net/jeps/142
http://mechanical-sympathy.blogspot.co.uk/2011/08/false-sharing-java-7.html
http://stackoverflow.com/questions/19892322/when-will-jvm-use-intrinsics
https://blogs.oracle.com/dave/entry/java_contented_annotation_to_help

Java8中@Contended和伪共享 进行缓存行填充相关推荐

  1. Java8的伪共享和缓存行填充--@Contended注释

    在我的前一篇文章<伪共享和缓存行填充,从Java 6, Java 7 到Java 8>中, 我们演示了在Java 8中,可以采用@Contended在类级别上的注释,来进行缓存行填充.这样 ...

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

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

  3. Java8中@Contended和伪共享

    @Contended和伪共享 原文:http://jingege.me/2016/05/31/sharing-false-and-contented/ 原文: http://robsjava.blog ...

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

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

  5. 高并发之伪共享和缓存行填充(缓存行对齐)(@Contended)

    ✨ 我是喜欢分享知识.喜欢写博客的YuShiwen,与大家一起学习,共同成长!

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

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

  7. 什么是伪共享?Java8如何使用@sun.misc.Contended避免伪共享?

    什么是伪共享 缓存系统中是以缓存行(cache line)为单位存储的.缓存行是2的整数幂个连续字节,一般为32-256个字节.最常见的缓存行大小是64个字节.当多线程修改互相独立的变量时,如果这些变 ...

  8. @sun.misc.Contended 解决伪共享问题

    先来看下什么叫做伪共享,转载自并发编程网 – ifeve.com 链接地址: 伪共享(False Sharing) 缓存系统中是以缓存行(cache line)为单位存储的.缓存行是2的整数幂个连续字 ...

  9. @Contended padding 伪共享

    @Contended和伪共享 原文: http://robsjava.blogspot.com/2014/03/what-is-false-sharing.html Java8引入了@Contente ...

最新文章

  1. 织梦 新建 php arclist,织梦arclist按照自定义字段来调用相关文章
  2. DPDK 大页内存原理(二十一)
  3. MFC窗口颜色的设置
  4. activemq 持久订阅_ActiveMQ群集,持久订阅者和虚拟主题可助您一臂之力
  5. java redis 多节点,Redis单机多节点集群部署,超简单
  6. 2018-3-10 unset 变量 ab测试
  7. python︱用asyncio、aiohttp实现异步及相关案例
  8. BUG--tomcat更改目录失败
  9. ExtJS在面向对象所作出的努力
  10. App 抓包工具一(Charles)
  11. Python 爬取科技部计划申报指南pdf文件并作词频分析
  12. Java练习之坦克大战!!!复制可以直接用!!!文章最后有飞机大战代码!!!
  13. python受益股_Python 金融: 看看 A股区块链板块
  14. 通过icon hash查IP地址
  15. Java Swing图书管理系统桌面软件附源码
  16. CTF-日常密码泄露分析溯源
  17. FFMpeg打开文件报错:Invalida data found when processing input
  18. matlab负序,Matlab对称分量法计算正序负序零序
  19. 93-世界这么大,我想出网关:欧洲十国游与玄奘西行
  20. 戴珊取代张勇成阿里法人代表 官方:只是B2B业务变更

热门文章

  1. Gradle配置阿里云镜像
  2. Java开源还是闭源
  3. 冀永楠:OCR的应用锦集及背后技术
  4. 来瞧瞧金砖大会的“护花使者”吧!
  5. python最小二乘法拟合曲线
  6. K7 GTX在SDI中的使用解析
  7. 小程序答题答题小程序
  8. ubuntu添加用户使用命令
  9. python延时一秒_python – 每个请求延迟1秒,不足以达到每小时3600
  10. 英语和数学不好是不是学不好编程?