范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Disruptor为什么会如此快(三)揭秘内存屏障(volatile)

  前言
  本文讨论什么是内存屏障(其实它是软件协调硬件工作的一个指令),以及如何应用volatile(在JAVA世界中内存屏障的语义是由volatile关键字来实现的),最后介绍在disruptor中如何应用的。
  什么是内存屏障
  它是一个CPU指令。我们在讨论CPU级别的东西,以便获得我们想要的性能(Martin著名的Mechanical Sympathy理论https://mechanical-sympathy.blogspot.com/2011/07/memory-barriersfences.html)。
  基本上,它是这样一条指令: a)确保一些特定操作执行的顺序; b)影响一些数据的可见性(可能是某些指令执行后的结果)。
  编译器和CPU可以在保证输出结果一样的情况下对指令重排序,使性能得到优化。插入一个内存屏障,相当于告诉CPU和编译器先于这个命令的必须先执行,后于这个命令的必须后执行。
  内存屏障另一个作用是强制更新一次不同CPU的缓存。例如,一个写屏障会把这个屏障前写入的数据刷新到缓存,这样任何试图读取该数据的线程将得到最新值,而不用考虑到底是被哪个cpu核心或者哪颗CPU执行的。
  和JAVA什么关系
  JAVA里有个关键字叫volatile, 在JAVA世界中内存屏障的语义是由volatile关键字来实现的  。JAVA 语言是支持多线程的,为了解决多线程的安全问题 JAVA 语言引进了 synchronized 同步块和 volatile关键字机制。
  volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的"可见性"。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
  为什么要使用volatile
  解决多线程下数据安全共享的问题;volatile变量修饰符如果使用恰当的话,它比synchronized的使用和 执行成本会更低 ,因为它不会引起线程上下文的切换和调度。
  volatile的实现原理
  那么Volatile是如何来保证可见性的呢?在x86处理器下通过工具获取JIT编译器生成的汇编指令来看看对Volatile进行写操作CPU会做什么事情。
  Java代码:
  instance = new Singleton();//instance是volatile变量
  汇编代码:
  0x01a3de1d: movb $0x0,0x1104800(%esi);0x01a3de24: lock addl $0x0,(%esp);
  有volatile变量修饰的共享变量进行写操作的时候会多第二行汇编代码,通过查IA-32架构软件开发者手册可知,lock前缀的指令在多核处理器下会引发了两件事情。  将当前处理器缓存行的数据会写回到系统内存。  这个写回内存的操作会引起在其他CPU里缓存了该内存地址的数据无效。
  处理器为了提高处理速度,不直接和内存进行通讯,而是先将系统内存的数据读到内部缓存(L1,L2或其他)后再进行操作,但操作完之后不知道何时会写到内存,如果对声明了Volatile变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存。但是就算写回到内存,如果其他处理器缓存的值还是旧的,再执行计算操作就会有问题,所以在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器要对这个数据进行修改操作的时候,会强制重新从系统内存里把数据读到处理器缓存里。
  小贴士:
  这两件事情在IA-32软件开发者架构手册的第三册的多处理器管理章节(第八章)中有详细阐述。
  Lock前缀指令会引起处理器缓存回写到内存 。Lock前缀指令导致在执行指令期间,声言处理器的 LOCK# 信号。在多处理器环境中,LOCK# 信号确保在声言该信号期间,处理器可以独占使用任何共享内存。(因为它会锁住总线,导致其他CPU不能访问总线,不能访问总线就意味着不能访问系统内存),但是在最近的处理器里,LOCK#信号一般不锁总线,而是锁缓存,毕竟锁总线开销比较大。在8.1.4章节有详细说明锁定操作对处理器缓存的影响,对于Intel486和Pentium处理器,在锁操作时,总是在总线上声言LOCK#信号。
  但在P6和最近的处理器中,如果访问的内存区域已经缓存在处理器内部,则不会声言LOCK#信号。相反地,它会锁定这块内存区域的缓存并回写到内存,并使用缓存一致性机制来确保修改的原子性,此操作被称为"缓存锁定",  缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据。
  一个处理器的缓存回写到内存会导致其他处理器的缓存无效 。 IA-32处理器和Intel 64处理器使用MESI(修改,独占,共享,无效)控制协议去维护内部缓存和其他处理器缓存的一致性。在多核处理器系统中进行操作的时候,IA-32 和Intel 64处理器能嗅探其他处理器访问系统内存和它们的内部缓存。它们使用嗅探技术保证它的内部缓存,系统内存和其他处理器的缓存的数据在总线上保持一致。例如在Pentium和P6 family处理器中,如果通过嗅探一个处理器来检测其他处理器打算写内存地址,而这个地址当前处理共享状态,那么正在嗅探的处理器将无效它的缓存行,在下次访问相同内存地址时,强制执行缓存行填充。
  volatile使用误区
  volatile很容易被误用,用来进行原子性操作。
  与使用 synchronized相比,声明一个 volatile 字段的区别在于没有涉及到锁操作。但特别的是对 volatile 字段进行" ++ "这样的读写操作不会被当做原子操作执行。同时测试了字符串拼接的操作,也是不安全的。下文中有代码已经证实 volatile 关键字修饰的变量在多线程写的情况下不安全。
  public class Counter { //    public volatile static int count = 0;       public volatilestatic StringBuilder count = new StringBuilder("aa");       public static void inc(String a){         //这里延迟1毫秒,使得结果明显         try {             Thread.sleep(1);         } catch (InterruptedExceptione) {           }             count .append(a+"-");       }       public static void main(String[]args) {         //同时启动1000个线程,去进行i++计算,看看实际结果         for (int i = 1; i <= 1000; i++) {             int finalI = i;             new Thread(new Runnable(){                 @Override                 publicvoid run() {                    Counter.inc(String.valueOf(finalI));                 }             }).start();         }         //这里每次运行的值都有可能不同,可能为1000         System.out.println("运行结果:Counter.count=" + Counter.count);     } }
  运行结果还是没有我们期望的 aa-XX-1000,下面我们分析一下原因。
  在 java 垃圾回收整理一文中,描述了 jvm 运行时刻内存的分配。其中有一个内存区域是 jvm 虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值 load 到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,变量的具体值 load 到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一幅图描述这些交互。
  read and load 从主存复制变量到当前工作内存
  use and assign 执行代码,改变共享变量值
  store and write 用工作内存数据刷新主存相关内容, 其中 use and assign 可以多次出现,但是这一些操作并不是原子性,也就是在 read load 之后,如果主内存 count 变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,所以计算出来的结果会和预期不一样。
  对于 volatile 修饰的变量, jvm 虚拟机只是保证从主内存加载到线程工作内存的值是最新的。
  例如假如线程 1 ,线程 2 在进行 read,load 操作中,发现主内存中 count 的值都是 5 ,那么都会加载这个最新的值
  在线程 1 堆 count 进行修改之后,会 write 到主内存中,主内存中的 count 变量就会变为 6
  线程 2 由于已经进行 read,load 操作,在进行运算之后,也会更新主内存 count的变量值为 6
  导致两个线程及时用 volatile 关键字修改之后,还是会存在并发的情况。
  暂且不管在多线程下对 volatile 修饰的变量进行修改是否安全的,但是在多线程下对 volatile 修饰的变量进行读操作是安全的,后一点是无可非议的。所以有了以下的结论:   volatile 的适用场景当只有一个线程可以修改字段的值,其它线程可以随时读取,那么把字段声明为 volatile 是合理的。
  对性能的影响
  内存屏障作为另一个CPU级的指令,没有锁那样大的开销,可以看之前文章
  Disruptor为什么会如此快 - (一)锁的成本的实验结果。内核并没有在多个线程间干涉和调度。
  Disruptor如何使用内存屏障
  下图是Disruptor的AbsttactSequencer源码截图。
  把Sequence定义为volatile 类型,供多线程共享。从截图可以看出gatingSequences在对象实例化时进行了初始化(写操作),多处进行读操作。这个与先前得出的结论颇为相似:  volatile 的适用场景当只有一个线程可以修改字段的值,其它线程可以随时读取,那么把字段声明为 volatile 是合理的。
  小结
  1、内存屏障是CPU指令,它允许你对数据什么时候对其他进程可见作出假设。在Java世界里,使用volatile关键字来实现内存屏障。使用volatile意味着不用被迫选择加锁,并且还能获得性能的提升。
  2、volatile的适用场景:当只有一个线程可以修改字段的值,其它线程可以随时读取,那么把字段声明为 volatile 是合理的。
  如果此文能帮小伙伴答疑解惑,请  关注「架构那些事儿」
  你的关注就是我的动力!

拿下12项全球第一!世界首款4nm芯片发布,不仅高端还将挑战高通点击关注,每天精彩不断!导读拿下12项全球第一!世界首款4nm芯片发布,不仅高端还将挑战高通!作为现代科技领域发展的核心,半导体芯片是十分重要的如今我们使用的智能手机平板电脑新能源MediaTek发布全新8K旗舰智能电视芯片Pentonic20002021年11月22日,MediaTek发布全新8K旗舰智能电视芯片Pentonic2000,拥有强大的AI引擎,支持MEMCAVS3解码VVC解码和画中画技术,用领先技术赋能新一支持中国芯片做大做强,普通中国人能做什么?这个问题是一个非常好的问题。要知道一个操作系统能在世上立足首先要培养生态,而芯片能得到市场的认可,是需要市场中的销量,一个芯片上市他并不是拿芯片摆到市场的货架上去叫卖,而是把芯片焊以企业总部来看全球市值前十高的科技公司腾讯摩天楼傲视群雄前言目前市值位居全球前十的科技型公司分别是苹果微软亚马逊谷歌脸书腾讯阿里巴巴台积电英伟达三星电子。中国科技巨头企业华为,因未在证券市场上市,没有具体的数值,所以并未入围榜单。不过我为什么很多人选择在银行买基金?年龄大的人喜欢在银行买基金,他们觉得更可靠,网上买可能对于老人操作上有些困难,我问过比我年长的人,办个小业务也要跑银行,为什么不开手机银行,有些业务,可以在家里就办了,有很多的老人一台手机使用多久换新才比较合适?手机使用多久换新比较合适?这个问题我想许多人都想知道,尤其是如今手机性能越来越强悍,价格也水涨船高,相比以往的换机概念已大相径庭,加上迭代更新的速度也越来越快,现在往往大家想换手机AI企业密集登陆资本市场商业模式仍是主要瓶颈日前,国内人工智能(AI)龙头商汤科技通过了港交所聆讯,中金公司海通国际和汇丰为其主承销商。下半年以来,国内AI企业迎来扎堆上市潮。除商汤科技外,AI四小龙企业均在积极奔赴资本市场苹果起诉NSOGroup以限制其恶意使用受到国家资助的间谍软件苹果今日对NSOGroup及其母公司发起诉讼,以使该公司为其针对性监控少数Apple用户的行为负责。该控告提供了新的信息,解释NSOGroup如何利用其Pegasus间谍软件侵害受从企业家院士看民营企业创新力民营企业家是民营企业实现科技创新的探索者组织者引领者。经确认,到目前为止,有5位民营企业科技工作者当选为中国工程院院士,他们是今年增选的宁夏吴忠仪表有限责任公司董事长马玉山,江苏康华为Mate50王者归来,5G回归共3种方案,花粉终于等到了还记得前几个月,在华为P50系列新品发布会上,余承东沮丧地说道没有办法,现在华为5G处理器只能当4G用,华为新机基本都不支持5G功能,这也让华为手机业务一度陷入停摆,不少业内人士甚有5G版本!华为Mate50Pro新增12512G版本,可惜售价太高据了解,前段时间美国已经对华为开放了一些产业链限制,也就是说接下来华为在制造手机上将会更顺利,并且有消息称华为已经在试图用强大的5G通讯技术来实现新机支持5G网络。具体来说,明年的
心级服务智能马桶,关爱您的健康几年前,如果提到智能马桶这个词,可能很多人都觉得这是一个稀罕物。但是随着近几年数字化进程加快,根据相关调查数据显示,智能马桶越来越普及,用户对于智能化马桶的接受度越来越高。中国移动自播时代,企业不懂直播怎么办?11月11日,用10余年的时间完成了从普通的日期到光棍节,再到双11的角色变换。无数网友早已习惯在这个特定的时间里守在电脑或手机屏幕前,做最后的购物冲刺。双11,经历时间的洗礼,成心级服务合作伙伴好帮手串码管理工具和家亲生态合作平台是合作伙伴智能设备入库一站式服务平台以及能力开放的对外集成展示平台,平台提供三大服务中心接入服务中心,能力服务中心,方案服务中心,合作伙伴可以在平台上尽情找合作找心级服务广大普通影迷的家庭影院时代真的到来了在刚过去的2021国庆假期,长津湖我和我的父辈等大片扎堆上映。随着经济的快速发展,人们对精神文化的需求日益提升,中国电影市场迎来蓬勃发展的新时期但同时也面临着如何持续供给高质量内容心级服务全屋智能是一种怎样的体验?当疲惫一天回到家,喜欢的灯光香氛和电视内容自动开启,耳边响起舒心的音乐,厨房的饭菜已自动烧好,那些曾经只有在电影中出现的场景,正在慢慢走进我们的家。日前,IDC发布中国智能家居设备心级服务不止能上网,WiFi还能智能感知?日常生活中你是否有遇到过这样的烦恼?外地工作,家里老人独居生活不放心?出门在外,担心室内防盗不安全?家中智能摄像头,屡屡被破解,网上公然贩卖,隐私问题何时休?红外传感器精度低误报频心级服务和家亲WiFi助手服务,打造智能家庭网络随着居民收入提高生活条件改善科学技术发展,人们的娱乐生活日益丰富,对于家庭网络的智能体验要求也越来越高。智能化的家庭网络不仅为用户提供高质量的上网服务,保障日常的上网需求,同时也可心级服务双十一抢购,网速不行怎么办?又到一年双十一,你是否已经沉浸在各大主播的直播间无法自拔?购物车是否已经加满了预购连接,就等一声令下?是否想到去年因为网速不够,而痛失的心动好物?你是否在纠结选择哪家宽带服务?!家心级服务快节奏的生活下,如何保护我们的健康?现在的生活节奏太快,年轻人活得就像是装满燃料的发动机,一直在不停地运转,但是再好的发动机如果你不爱护她不保养她,也会有闹情绪甚至罢工的时候。真到了这种时候,你是不是又会拍着大腿仰天心级服务快节奏的生活下,如何保护我们的健康?现在的生活节奏太快,年轻人活得就像是装满燃料的发动机,一直在不停地运转,但是再好的发动机,如果你不爱护她不保养她,也会有闹情绪甚至罢工的时候。真到了这种时候,你是不是又会拍着大腿仰管住嘴,迈开腿!Yolanda智能营养秤帮你监测每日食物热量摄入最近比较忙,出去运动的时间也很少。没有运动的时间,就只能依靠控制饮食来达到控制体重的目的。从上个月开始,减少了碳水类的摄入,减少了米饭的摄入,改为多吃一些沙拉豆腐。结果每天都能稳定