java中什么是 伪共享_【Java】聊聊多线程中的伪共享现象

首页

专栏

java

文章详情

0

聊聊多线程中的伪共享现象

109340.html小强大人发布于 1 月 27 日

什么是伪共享?

讲伪共享之前,让我们先乘坐时光机,回到大学课堂,来重温下计算机组成原理的基础知识。我们知道,CPU和内存的运行速度相差很大,为了解决这个问题,在CPU和内存之间会加一级或多级高速缓存(Cache)。这个Cache一般是集成在CPU内部的,所以也叫CPU Cache。下图是一个两级Cache的CPU-Cache-内存架构。

fb472a89582457dc9319c0b3bc2e2bcf.png

数据在Cache中是按行存储的,其中每一行称为一个Cache行,如下图所示。它是CPU与内存数据交换的基本单位。Cache行的大小一般为2的幂次字节数。

eb608aedde4f3405349e9fe46b480915.png

CPU-Cache-内存架构的工作原理是这样的:当CPU访问某个变量时,首先会从CPU Cache里查看是否有该变量,如果有直接获取并返回,否则从内存中获取,然后把该变量所在内存区域的一个Cache行大小的内存数据复制到Cache中,这就是我们所说的局部性原理。由于存放到Cache行的不是单个变量,而是一个内存块数据,所以会出现多个变量放在一个Cache行中。当多个线程同时修改同一个缓存行里面的不同变量时,由于同一时刻只允许一个线程操作缓存行,一个线程成功获取缓存行的修改权时,其他线程会互斥等待,并且由于缓存一致性协议,其他线程相应的缓存行会失效,需要重新从内存获取数据,这无疑耗费了更多时间。所以相比把每个变量放在不同的缓存行,性能反而有所下降,这就是伪共享现象。

如下图所示,变量x,y放在同一个缓存行中,线程1操作缓存行的x变量,线程2操作y变量。

76bb4eceae875ab7a1dd9872bb864b3c.png

如何避免伪共享呢?

在JDK1.8之前,通常是通过字节填充的方式。什么意思呢?就是用到一个变量时,补充额外的若干辅助变量,使得这些变量刚好填充满一个缓存行,这样就避免了多个变量存放在一个缓存行中。具体看下面示例代码:

static final class PaddedLongField {

public volatile long value = 0L;

public long p1,p2,p3,p4,p5,p6;

}

假如CPU Cache行大小为64字节,那么我们这里填充了6个long型的变量,每个long型变量占8个字节,加上value一共7*8=56字节,另外,别忘了PaddedLongField是一个类对象,对象头还要占用8个字节,所以一个PaddedLongField对象占用64个字节,刚好填充满一个缓存行。

在JDK1.8之后,提供了一个@sun.misc.Contended注解,用来解决伪共享问题。此时,我们上面的代码就可以简化了:

@sun.misc.Contended

static final class PaddedLongField {

public volatile long value = 0L;

}

@Contended注解不仅可以修饰类,也可以修饰变量:

2c5fd3d81e08943e658c409bf9936665.png

JUC源码里很多使用这个注解的,比如Thread类里threadLocalRandom相关的变量:

05a85b7c4ab00b3c0982ab31cc896cfb.png

再比如LongAdder内部用到的Cell也用了这个注解:

f754481e901017ff3fb3dd036033739c.png

再比如ForkJoinPool类上面也修饰了:

e1c5eb920ebc08bb9f397012c3168cc8.png

最后需要注意下,@Contended注解默认只用于Java核心类,比如rt.jar下的类。如果我们应用程序中想使用这个注解,需要添加一个JVM参数:-XX:-RestrictContended,填充的默认宽度为128字节,若需自定义宽度则可以用另一个参数:-XX:ContendedPaddingWidth=xxx

本文就到这里啦,若这篇文章对你有所帮助的话,点个赞再走叭!谢谢支持!

参考资料:

《Java并发编程之美》

java

阅读 53更新于 1 月 27 日

赞收藏

分享

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

109340.html

小强大人

9声望

1粉丝

关注作者

0 条评论

得票时间

109340.html

提交评论

109340.html

小强大人

9声望

1粉丝

关注作者

宣传栏

什么是伪共享?

讲伪共享之前,让我们先乘坐时光机,回到大学课堂,来重温下计算机组成原理的基础知识。我们知道,CPU和内存的运行速度相差很大,为了解决这个问题,在CPU和内存之间会加一级或多级高速缓存(Cache)。这个Cache一般是集成在CPU内部的,所以也叫CPU Cache。下图是一个两级Cache的CPU-Cache-内存架构。

fb472a89582457dc9319c0b3bc2e2bcf.png

数据在Cache中是按行存储的,其中每一行称为一个Cache行,如下图所示。它是CPU与内存数据交换的基本单位。Cache行的大小一般为2的幂次字节数。

eb608aedde4f3405349e9fe46b480915.png

CPU-Cache-内存架构的工作原理是这样的:当CPU访问某个变量时,首先会从CPU Cache里查看是否有该变量,如果有直接获取并返回,否则从内存中获取,然后把该变量所在内存区域的一个Cache行大小的内存数据复制到Cache中,这就是我们所说的局部性原理。由于存放到Cache行的不是单个变量,而是一个内存块数据,所以会出现多个变量放在一个Cache行中。当多个线程同时修改同一个缓存行里面的不同变量时,由于同一时刻只允许一个线程操作缓存行,一个线程成功获取缓存行的修改权时,其他线程会互斥等待,并且由于缓存一致性协议,其他线程相应的缓存行会失效,需要重新从内存获取数据,这无疑耗费了更多时间。所以相比把每个变量放在不同的缓存行,性能反而有所下降,这就是伪共享现象。

如下图所示,变量x,y放在同一个缓存行中,线程1操作缓存行的x变量,线程2操作y变量。

76bb4eceae875ab7a1dd9872bb864b3c.png

如何避免伪共享呢?

在JDK1.8之前,通常是通过字节填充的方式。什么意思呢?就是用到一个变量时,补充额外的若干辅助变量,使得这些变量刚好填充满一个缓存行,这样就避免了多个变量存放在一个缓存行中。具体看下面示例代码:

static final class PaddedLongField {

public volatile long value = 0L;

public long p1,p2,p3,p4,p5,p6;

}

假如CPU Cache行大小为64字节,那么我们这里填充了6个long型的变量,每个long型变量占8个字节,加上value一共7*8=56字节,另外,别忘了PaddedLongField是一个类对象,对象头还要占用8个字节,所以一个PaddedLongField对象占用64个字节,刚好填充满一个缓存行。

在JDK1.8之后,提供了一个@sun.misc.Contended注解,用来解决伪共享问题。此时,我们上面的代码就可以简化了:

@sun.misc.Contended

static final class PaddedLongField {

public volatile long value = 0L;

}

@Contended注解不仅可以修饰类,也可以修饰变量:

2c5fd3d81e08943e658c409bf9936665.png

JUC源码里很多使用这个注解的,比如Thread类里threadLocalRandom相关的变量:

05a85b7c4ab00b3c0982ab31cc896cfb.png

再比如LongAdder内部用到的Cell也用了这个注解:

f754481e901017ff3fb3dd036033739c.png

再比如ForkJoinPool类上面也修饰了:

e1c5eb920ebc08bb9f397012c3168cc8.png

最后需要注意下,@Contended注解默认只用于Java核心类,比如rt.jar下的类。如果我们应用程序中想使用这个注解,需要添加一个JVM参数:-XX:-RestrictContended,填充的默认宽度为128字节,若需自定义宽度则可以用另一个参数:-XX:ContendedPaddingWidth=xxx

本文就到这里啦,若这篇文章对你有所帮助的话,点个赞再走叭!谢谢支持!

参考资料:

《Java并发编程之美》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/559802.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java多个mapreduce_java – 在hadoop中运行多个MapReduce作业

我想运行一系列map reduce工作,所以最简单的解决方案似乎是jobcontroller.说我有两个工作,job1和job2.我想在job1之后运行job2.嗯,它遇到了一些问题.经过几个小时的调试后,我将代码缩小到以下几行:JobConf jobConf1 new JobConf();JobConf jobConf2 new JobConf()…

java用户界面项目_结对项目(带图型用户界面)Java实现【柴政-陈起廷】

对分数及整数的计算/**** 相加操作*/ADD("") {Overridepublic String calculate(String a, String b) {boolean flagA a.contains("/");boolean flagB b.contains("/");//两个都是分数if (flagA && flagB) {int[] anInt ResolveUtil.…

java securerandom使用_Java中的SecureRandom nextBytes()方法

用户指定的随机字节数可以使用nextBytes()类java.security.SecureRandom中的方法获得。该方法需要一个参数,即一个随机字节数组,它返回用户指定的随机字节。演示此的程序如下所示-示例import java.security.*;import java.util.*;public class Demo {pub…

java 跨类 调用 model_Model.java中的这两个方法,为什么不能在子类中调用,或者包内调用也行啊。...

JFinal 你好,想跟你请教个问题:Model.java中的这两个方法,为什么不能在子类中调用,或者包内调用也行啊。/*** Find model.*/SuppressWarnings("unchecked")private List find(Connection conn, String sql, Object... p…

mysql n 识别_mysql – 不能有“不识别”的N:M关系吗?

我的数据库ERM(实体关系模型)有一个TEACHER实体类型,它与SUBJECT_MODULE实体类型相关(因为每个主题中的不同模块由不同的教师讲授,对于某些模块,甚至每个模块中的不同章节都可以通过不同的教师)通过TEACH关系类型.这是一种N:M的关系,因为每个教师都可以教授许多学科…

新闻资讯java开发_新闻资讯app开发的功能与意义

获取新闻的目的因人而异,但对获取新闻的需求是一样的。现在是移动互联网的时代。人们不再想依靠传统的手段,而把便利作为获取服务的核心。因此,开发新闻咨询app是必要的。其到来不仅意味着获得新闻登上新的阶梯,还因为画出了圆满的…

JAVA中注解controller_SpringMVC之基于注解的Controller

参考博客:https://www.cnblogs.com/qq78292959/p/3760560.htmlController注解:传统风格的Controller需要实现Controller接口,而现在我们只需要用注解就行了。基于注解的控制器有几个优点,1.一个控制器可以处理多个action(动作)&am…

c java json_cJSON_json包的C语言解析库

cJSON库描述CJSON是一个用于解析JSON包的C语言库,库文件为cJSON.c和cJSON.h, 所有的实现都在这两个文件中。原作者的地址cJSON。JSON包的解析例如有一个JSON的数据包如下:{"rxpk": [{"tmst": 1868500100,"time"…

e语言mysql中文_大佬们E语言连接MYSQL输出中文乱码怎么破

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼.版本 2.支持库 mysql.支持库 iext.程序集 窗口程序集_启动窗口.子程序 _按钮1_被单击数据库连接句柄 = 连接MySql (“127.0.0.1”, “root”, “zkqingfish*”, “mu_game_1”, 3306) 执行SQL语句 (连接句柄, “set na…

java中删除最大的数,【Java练习】删除字符串中字符个数最少的字符

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼输入:asdasdas输出:asasas[java] view plain copyprint?1.package com.iotex;2.3.import java.util.ArrayList;4.import java.util.Collections;5.import java.util.Comparator;6.import java.util.HashMap…

php实时上传多张图片,PHP实现多张图片上传预览功能

PHP实现多张图片上传预览功能,支持左右移动图片切换位置、删除图片,限制图片上传的数量等-向左移动图片function reverse_left(obj) {var obj_li obj.parents("li");var obj_prev obj_li.prev("li");if (obj_prev.hasClass("…

centos php 默认安装目录,centos系统中的软件安装目录在哪

centos系统中软件的默认安装目录一般在/usr/local或者/opt中。我们还可以通过whereis命令来查看软件的实际安装路径。命令:whereis功能介绍:在特定目录中查找符合条件的文件。这些文件的烈性应属于原始代码,二进制文件,或是帮助文…

php代码丑,php – 屏幕截图你生命中见过的最丑陋的HTML

我正在使用PHP和libtidy来尝试筛选可能是历史上最糟糕和最不正确的HTML表格使用情况.该站点关闭了几个table,tr,td,font或bold标签,并且一致地嵌套了表中的许多不同的表层.示例代码段:Home Team - WildcatsAway Team - Polar BearsRosters1 Baird, T2 Knight, P8 Mi…

百度指数 php,百度指数是什么?百度指数有什么用?百度指数怎么用?

做SEO必知的第一步:百度指数【百度指数地址】百度指数是用以反映关键词在过去30天内的网络曝光率及用户关注度! 它能形象地反映该关键词的每天的变化趋势!百度指数是以百度网页搜索和百度新闻搜索为基础的免费海量数据分析服务,用…

php获取全部sessionid,php怎么获取所有的sessionid?或获取所有的session

php怎么获取所有的sessionid?或获取所有的sessionphp 如何获取所有的 sessionid ?或获取所有的session就是想通过一个.php文件读取所有的 sessionid ?或获取所有的session ??sessionphp------解决方案----------------…

php atlas,apache atlas是什么

Atlas是一组可伸缩和可扩展的核心基础治理服务——使企业能够有效和高效地满足Hadoop中的遵从性需求,并允许与整个企业数据生态系统进行集成。Apache Atlas为组织提供开放的元数据管理和治理能力,以建立其数据资产的目录,对这些资产进行分类和…

matlab heaviside,Matlab编写的Lyapunov指数计算程序汇总.doc

Matlab编写的Lyapunov指数计算程序汇总matlab编写的Lyapunov指数计算程序汇总申明:以下各程序为个人在网络上收集的Lyapunov指数计算程序,未经过验证,不保证程序的正确性和计算结果的正确性,请大家见谅,也欢迎大家探讨…

php2588,搞清楚一下必胜2588z和2582z哪个好点?都有些什么区别?内幕评测分析

这二个必胜2588z和2582z区别不是很大的哈,款式和配置是差不多的,只是必胜2582Z 2052Z更强一些,看个人需要吧,不过家用的话,这两款都是可以的,我自己用的是必胜2582Z 2052Z,款式多大气的&#xf…

超表面透镜相位matlab,基于超透镜的小F数大景深镜头的设计方法及应用与流程...

本发明涉及基于超透镜的小f数大景深镜头的设计方法及应用。背景技术:监控系统中采用的透镜往往要求具有尽量高的成像分辨率和尽量大的景深,通常情况下,高分辨率的透镜一般具有较小f数,大的景深又要求焦距较短。但是利用传统透镜的…

获取php数组最后,php获取数组最后一个值的2种方法

摘要:这篇文章主要介绍了PHP获取数组最后一个值的2种方法,本文直接给出实现代码,代码中包含注释,需要的朋友可以参考下$arrayarray(1,2,3,4,5);echo $array[count($array)-1];//计算数组长度,然后获取数组最后一个元素,如果数组中最后一个元素…