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

彻底理解volatile

  volatile原理
  在Java并发编程中synchronized和volatile扮演者重要的角色,volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性和程序执行的有序性。如果volatile使用恰当的话,它比** **synchronized的使用和执行成本更低,因为它不会引起线程上下文切换和调度。 我们了解一下计算机,例如在我们工作当中大多数都是多核,由于CPU和物理主存速度不一致问题,为了解决CPU读取内存指令和数据效率问题,诞生了CPU高速缓存。
  private volatile instance = new Singleton();
  在生成汇编代码时会在volatile修饰的共享变量进行写操作的时候会多出Lock前缀的指令 ,Lock前缀指令在多核处理器下会发生两件事。  将当前处理器缓存行的数据写回系统内存;  这个写回内存的操作会使得其他CPU里缓存了该内存地址的数据无效
  为了提高处理器速度,首先处理器不直接和内存进行通信,而是先将系统内存的数据读到高速缓存(L1,L2,L3)后再进行操作,但是操作何时会写到内存,如果对声明volatile的变量进行写操作,JVM 就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写到系统内存。但是就算写到内存,如果其他处理器存在的值还是旧的,再执行计算操作就会有问题。所以,在多处理器下,为了保证各处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址别修改,就会将当前处理器的缓存行设置为无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。 因此,我们得出一下结论:  Lock前缀的指令会引起处理器缓存写回内存;  一个处理器的缓存回写到内存会导致其他处理器的缓存失效;  当处理器发现本地缓存失效后,就会从内存中重读该变量数据,即可以获取当前最新值。
  这样针对volatile变量通过这样的机制就使得每个线程都能获得该变量的最新值,即可见性。  可见性
  那么下面我们通过代码证明volatile如何保证可见性? 保证不同线程对这个变量进行操作时的可见性,即变量一旦改变所有线程立即可以看到  /**  * 保证可见性  */ public class ResourceData {      // voliate 关键字能保证变量的可见性,多个线程修改同一个变量时,一个线程修改完,另一个线程获取到的是修改之后的值。     private volatile int number = 0;      public void add() {         this.number = 10;     }       public static void main(String[] args) {         ResourceData resourceData = new ResourceData();          new Thread(() -> {             System.out.println(Thread.currentThread().getName() + "	 come in ");             try {                 TimeUnit.SECONDS.sleep(3);                 resourceData.add();                 System.out.println(Thread.currentThread().getName() + "	 update number value " + resourceData.number);             } catch (InterruptedException e) {                 e.printStackTrace();             }         }, "AA").start();           // 第二个线程是main         while (resourceData.number==0) {          }         System.out.println(Thread.currentThread().getName()+"	 mission is over ,main get number value :" +resourceData.number);     } } AA  come in  AA  update number value 10
  如果共享变量不加volatile ,没有可见性,程序无法停止,加了volatile保证可见性,程序可以停止。
  原理解释:  没有添加volatile关键字,线程A对共享变量改变了以后将number修改为10,主线程(线程B)访问number的值还是0,这就是不可见。  添加volatile之后,线程A对共享数据进行了改变以后,那么main线程再次访问,number的值就是改变之后的number=10  原子性
  不保证原子性,代码实现:  /**  * 不保证原子性  */ public class ResourceData2 {      // volatile 关键字不能保证变量的原子性,当多个线程修改一个变量的时候可能回出现写丢失的情况。     // 如何保证数据的原子性呢     private volatile int number = 0;      // AtomicInteger 包装类可以保证变量的原子性     AtomicInteger atomicInteger = new AtomicInteger();     public  void addAtomic() {         atomicInteger.getAndIncrement();     }      public void add() {         number++;     }      public static void main(String[] args) {         ResourceData2 resourceData = new ResourceData2();         for (int i = 0; i <20 ; i++) {             new Thread(()-> {                     for (int j = 0; j < 1000; j++) {                         resourceData.add();                         resourceData.addAtomic();                     }             },String.valueOf(i)).start();         }          // 等待上面的线程全部计算完,再通过main线程获取最终的结果         while (Thread.activeCount()>2) {             // 指main 和Gc             Thread.yield();         }         System.out.println(Thread.currentThread().getName()+"	 finally number value :"                 +resourceData.number+"	 finally atomicInteger value :"+resourceData.atomicInteger);     } } main  finally number value :19778  finally atomicInteger value :20000
  预期结果是:20000,但是实际结果是:19778,那么是什么原因导致的呢?  首先对于一读一写操作,不会有数据问题 ,因为假设主内存的共享变量number=1,需要对主内存的number++处理,对于两个线程T1、T2如果是一读一写的操作是不会有数据丢失的情况,某一时刻,t1抢到CPU的执行权,将共享数据读回T1的工作内存,进行number++的操作,这个时候number=2,将2从工作内存写回到主内存中。写回后马上通知T2线程,将number=2读到T2的工作线程,所以不会造成数据丢失问题。  对于两个写,会出现数据问题,假设主内存的共享变量number=0,需要对主内存进行10次的number++处理,最终的结果就是10,对于两个线程T1、T2如果是两个写的操作会造成数据丢失的情况,T1和T2将主内存的共享数据读取到各自的工作内存去,某一时刻,T1线程抢到CPU的执行权,进行number++的处理,将工作内存中的number=1写回到主内存中,就在这一刻,T2也抢到CPU执行权,进行number++的处理,这个时候number++后的结果也等于1,T1将number=1写回到主内存中去,并通知T2线程,将主内存中的number=1读到T2的工作内存中去,这个时候对于T2,它之前也进行了一次number++的操作将会无效,回重新进行一次number++的操作。这也数据也就写丢了一次,那么10次number++后的结果也就不会等于10。  禁止指令重排
  重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段,有时候会改变程序语句的先后顺序(不存在数据依赖关系,可以重排序;存在数据依赖关系,禁止重排序) 重排序的分类和执行流程  编译器优化的重排序:编译器在不改变单线程串行语义的前提下,可以重新调整指令的执行顺序  指令级并行的重排序:处理器使用指令级并行技术来将多条指令重叠执行,若不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序  内存系统的重排序:由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是乱序执行
  数据依赖性:若两个操作访问同一变量,且这两个操作中有一个为写操作,此时两操作间就存在数据依赖性(存在数据依赖关系,会禁止重排序,因为会导致程序运行结果不同), 如果不存在依赖关系,可以重新排序。
  如果本文对你有帮助的话,欢迎点赞,非常感谢,欢迎关注公众号: 阿福聊编程

在曹操眼中有3位大将无可替代,不是关羽也非张辽,而是这3人历史上有一则经典典故叫做关羽温酒斩华雄,此事发生在东汉末年群雄争霸的时刻,刘备因为有了他这名骁勇善战的大将屡次在战役中胜出,种种缘由使得关羽成为曹操拉拢的对象。在徐州一战中,关羽因霍福德凯尔特人球星为什么36岁高龄仍能签下数千万养老合同?三十六岁签下两千万合同,终老一生,他凭什么比霍华德还幸运?身高2。08米的霍福德曾两次夺得NCAA总冠军,也曾是王牌诺阿的四号位搭档。然而一进入联盟,二十一岁的探花秀却要从绿叶做起足协要是无法解决武汉三镇的质疑,不妨参考下长沙某幼儿园的方法官方通报北京国安放弃中超第33轮对上海海港的联赛。除了国安,本轮还有河北队天津津门虎梅州客家弃权,这几支球队均被判03负。这让山东泰山直接躺赢,积分榜到达了榜首。这下武汉三镇就不乐汤普森合同到期后可能离开勇士加盟湖人?据Heavy记者SeanDeveney报道,一位西部高管透露,克雷汤普森有可能在当前合同结束后离开勇士,并考虑加盟湖人。他会加以考虑,该高管表示,你知道,他小时候一直看着爸爸打球,新势力轿跑纯电动汽车哪吒S耀世版探店嗨,大家好,给大家看一下哪吒S(参数丨图片)这款车,其实这款车呢,抓住了哪吒汽车的精髓,代表了哪吒汽车这个品牌的气质,其实哪吒S这款车的售价区间呢,也很广泛,从19。98万元到33煮熟的鸭子不会飞,山东泰山难逆转,武汉三镇成后金元中超新势力本赛季的中超联赛已经进入尾声,在中超联赛第33轮的一场焦点战中,武汉三镇坐镇武汉体育中心,凭借斯坦丘的直接任意球破门和戴维森的点射,以20击败浙江队,33轮过后,积分已经达到75分诗评丨周瑟瑟诗是古老又常新的讲述,胡弦式的向内勘探的本土经验诗是古老又常新的讲述,胡弦式的向内勘探的本土经验文周瑟瑟讲古是典型的胡弦式的诗歌。身处当代频频回望过去是胡弦诗歌的惯常姿态,从鲜活的生命里看见更加鲜活的死亡,胡弦的诗歌由此而具有了年度盘点2022年白酒行业花开四方跨界奔跑2022年转瞬即逝,生活环境与消费方式的剧变,导致消费者在决策过程中变得更为务实理智和大胆,这也将极大地影响原有的消费趋势与商业竞争格局。变化之下,2022年快消行业发展出现了不同JVM为什么需要有栈协程旧有的servlet生态的线程模型首先我们先要聊一聊现在我们用的最多的servlet的执行模型是什么这个dispatch其实就是一个EventLoop或者说是一个selector来讣告!超快光学技术知名专家陈国夫逝世我国超快光学技术领域的知名专家陈国夫同志,因病医治无效,于2022年12月25日在西安逝世,享年82岁。陈国夫同志1940年10月出生于广东省,1968年毕业于北京大学。曾任中国科有了这项技术,电动车无敌了?Hello,大家好!我是Mogo前两天给大家分享了一下纯电动之外的新能源,看来看去大家一直认为还不如电动车靠谱。平心而论,电动车是一种天然高效的载具,但为什么大家依旧排斥?无外乎是
重庆山腰发现遗弃别墅群,30套房只住一个大爷,经历令人悲哀秋日生活打卡季继上次在北碚缙云山上发现了一片废弃的别墅群,最近有网友朋友也在给我留言并给我推荐了这个地方,于是趁着空闲时间,我就专门来到这里探寻一番,一看之下,好生羡慕,也好生心疼九言寒露至,微风凉,珍重此时,秋意浓,情更浓,心暖依然所谓内心的快乐,是一个人过着健全的正常的和谐的生活所感到的快乐。寒露至,微风凉,珍重此时,秋意浓,情更浓,心暖依然。尽管眼下有点困难,但日后一定会开花结果。无论过去如何,我们一定要广州出发肇庆2天游,走进广宁宝锭山漫步岩前村,游紫云谷景区今天给大家介绍一条肇庆2天游行程,游砚坑紫云谷景区,畅游山泉泳池,走进广宁宝锭山,漫步岩前村,01肇庆紫云谷一个小众,却不为人知的世外桃源。100的绿意盎然,呼吸的每一口空气都是甜奋进新征程建功新时代非凡十年基础设施建设夯实发展之基基础设施是经济社会发展的重要支撑和必备条件。党的十八大以来,在以习近平同志为核心的党中央坚强领导下,在社会各界共同努力下,我国交通能源水利和新型基础设施发展取得了历史性成就,现代综华表上的神兽在天安门南北门外,分别耸立有一对雕刻精美挺拔秀丽的云龙华表。据淮南子主术训记载,远在尧舜时代就有街头设表木的做法,用以王者纳谏,征求民众意见以治天下。到秦汉时期,表木被改为指路标,龚俊出席活动保镖开路,人数过多惹路人嘲讽小小演员那么大排场终于又有杂志举办时尚活动啦!前段时间围观了一系列阿那亚品牌大秀,看了明星生图又扒拉了他们造型,还是觉得有些意犹未尽,毕竟大秀主办方都是单一品牌,大家造型风格差距不大,到场明星也有限三观不同,永远不会是一路人有人说,聊天能把一个人的情绪提升到极致,要么兴奋,要么愤怒。深以为然,因为聊天能够促使人的大脑神经变得敏感,也变得越来越细腻。各种讯息铺天盖地,究竟是糖衣炮弹,还是充满火药,一切皆早期港圈神仙打架刘嘉玲在蓝洁瑛身边像路人,向太艳压关之琳上世纪八九十年代的香港娱乐圈是神仙打架的年代,那个时候电影圈之所以繁华,得益于香港娱乐圈的那一波美女帅哥的出现,香港电影的辉煌时期火遍整个亚洲,当时很多人也借此机会走向了好莱坞,辉回顾女子坐地铁穿着清凉,腿上穿个箍用链子牵着,路人悄悄偷看在现代这个文明开放的社会,人人都有追求审美自由的权利。爱美之人,人皆有之。人都喜欢吸引别人的注意力,尤其是对于颜值出众的女孩来说,她们更乐于在别人面前展示自己的魅力和优秀。然而,追好声音廖昌永退赛真相曝光,李玟当场发飙,导演组败光路人缘头条创作挑战赛浙江卫视的中国好声音2022目前还在持续热播当中,在豆瓣上的评分依然停留在4。5分,就目前的情况来看,口碑很难逆风翻盘了,之所以会遭到网友们的群嘲,并非偶然,而是必然2岁幼儿被一巴掌扇趴在地上,狠心的姑父在撒谎他自己摔倒的一个成年人,一个巴掌扇趴一个幼儿,仅仅是2岁年龄。幼儿站着被一个大人直接扇倒在地上,可见这力度有多大,有多重。下手忒狠了,一个大人跟幼儿一般见识,情绪有多糟糕,人就有多暴力。来自广