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

Java并发编程初识Volatile(概念与特性)

  一、什么是Volatile概念
  volatile是Java中的关键字,用来修饰会被不同线程访问和修改的变量。volatile可以说是java虚拟机提供的最轻量级的同步机制。二、特性1、保证可见性概述
  保证不同线程对这个变量进行操作时的可见性,即变量一旦改变所有线程立即可见。代码验证public class VolatileSeeDemo {     static boolean flag=true;     public static void main(String[] args) {         new Thread(() -> {             System.out.println(Thread.currentThread().getName()+"	 come in");             while (flag) {              }             System.out.println(Thread.currentThread().getName()+"	 come out");         }, "t1").start();         //线程睡眠2s         try{TimeUnit.MILLISECONDS.sleep(2000);}catch(Exception e){e.printStackTrace();}         flag=false;         System.out.println(Thread.currentThread().getName() + "	 修改完成");     } }
  输出结果:程序无法正常结束
  线程t1中为何看不到被主线程main修改为false的flag的值?
  问题可能:主线程修改了flag之后没有将其刷新到主内存,所以t1线程看不到。主线程将flag刷新到了主内存,但是t1一直读取的是自己工作内存中flag的值,没有去主内存中更新获取flag最新的值。
  解析
  由于普通变量没有可见性,无法感知结果的变化,主线程将flag刷新到了主内存,但是t1一直读取的是自己工作内存中flag的值,没有去主内存中更新获取flag最新的值。 故while里面的flag始终是ture,因此导致程序一直在while循环中。
  下面用volatile修饰flagpublic class VolatileSeeDemo {     static volatile boolean flag=true;     public static void main(String[] args) {         new Thread(() -> {             System.out.println(Thread.currentThread().getName()+"	 come in");             while (flag) {               }             System.out.println(Thread.currentThread().getName()+"	 come out");         }, "t1").start();         //线程睡眠2s         try{TimeUnit.MILLISECONDS.sleep(2000);}catch(Exception e){e.printStackTrace();}         flag=false;         System.out.println(Thread.currentThread().getName() + "	 修改完成");     } }
  运行结果:程序正常结束
  解释
  由于flag被volatile修饰,故其具有可见性,flag的每一次修改都会被发现,flag由true变为false,循环结束。volatile修改的变量特点线程中读取的时候,每次读取都会去主内存中读取共享变量最新的值,然后将其复制到工作内存 。线程中修改了工作内存中变量的副本,修改之后会立即刷新到主内存 。volatile变量的读写过程
  Java内存模型中定义的8种工作内存与主内存之间的原子操作
  read(读取) load(加载) use(使用) assign(赋值) store(存储) write(写入)  lock(锁定) unlock(解锁)
  read: 作用于主内存 ,将变量的值从主内存传输到工作内存,主内存到工作内存
  load: 作用于工作内存,将read从主内存传输的变量值放入工作 内存变量副本 中,即数据加载
  use: 作用于工作内存,将工作内存变量副本的值传递给执行引擎,每当JVM遇到需要该变量的字节码指令时会执行该操作
  assign: 作用于工作内存,将从执行引擎接收到的值赋值给工作内存变量,每当JVM遇到一个给变量赋值字节码指令时会执行该操作
  store: 作用于工作内存,将赋值完毕的工作变量的值写回给主内存
  write: 作用于主内存 ,将store传输过来的变量值赋值给主内存中的变量
  由于上述只能保证单条指令的原子性,针对多条指令的组合性原子保证,没有大面积加锁 ,所以,JVM提供了另外两个原子指令 :
  lock: 作用于主内存 ,将一个变量标记为一个线程独占的状态,只是写时候加锁,就只是锁了写变量的过程。
  unlock: 作用于主内存 ,把一个处于锁定状态的变量释放,然后才能被其他线程占用2、没有原子性概述
  原子性指的是一个操作是 不可中断 的,即使是在多线程环境下,一个操作一旦开始就不会被其他线程影响。代码验证class MyNumber{     static int number=0;     public static void add(){         number++;     } } public class VolatileNoAtomicDemo {     public static void main(String[] args) {         for (int i = 0; i < 10; i++) {             new Thread(() -> {                 for (int i1 = 0; i1 < 1000; i1++) {                     MyNumber.add();                 }             }, String.valueOf(i)).start();         }         //暂停3s线程        try{TimeUnit.MILLISECONDS.sleep(3000);}catch(Exception e){e.printStackTrace();}         System.out.println(Thread.currentThread().getName() + "	 +myNumber:" + MyNumber.number);     } }
  输出结果
  理论上是输出10*1000=1w的,为什么这里只有4312呢?字节码角度分析
  原子性指的是一个操作是 不可中断 的,即使是在多线程环境下,一个操作一旦开始就不会被其他线程影响。public void add () {     i++; // 不具备原子性 ,该操作是先读取值,然后写回一个新值,相当于原来的值加上1,分3步完成  }
  如果第二个线程在第一个线程读取旧值和写回新值期间读取i的域值 ,那么第二个线程就会与第一个线程一起看到同一个值,
  并执行相同值的加1操作,这也就造成了线程安全失败(即一个线程更新数据完成后去刷新主内存,导致正在修改数据的线程直接结束,因此造成部分i++失效,而循环次数一直在累加),因此对于add方法必须使用synchronized修饰,以便保证线程安全.不保证原子性原因
  多线程环境下, "数据计算"和"数据赋值" 操作可能多次出现,即操作非原子 。若数据在加载之后,若主内存count变量发生修改之后,由于线程工作内存中的值在此前已经加载,从而不会对变更操作做出相应变化,即私有内存和公共内存中变量不同步,进而导致数据不一致 。
  对于volatile变量,JVM只是保证从主内存加载到线程工作内存的值是最新的,也就是数据加载时是最新的。
  由此可见volatile解决的是变量读时的可见性问题,但无法保证原子性,对于多线程修改共享变量的场景必须使用加锁同步既然一修改就是可见,为什么还不能保证原子性?
  volatile主要是对其中部分指令做了处理
  要use(使用)一个变量的时候必需load(载入),要载入的时候必需从主内存read(读取)这样就解决了读的可见性。
  写操作是把assign和store做了关联(在assign(赋值)后必需store(存储) )。store(存储)后write(写入)。
  也就是做到了给一个变量赋值的时候一串关联指令直接把变量值写到主内存。
  就这样通过用的时候直接从主内存取,在赋值到直接写回主内存做到了内存可见性。 注意蓝色框框的间隙…o( ﹏ )o
  总结
  读取赋值一个volatile变量的情况
  read-load-use和 assign-store-write 成为了两个不可分割的原子操作, 但是在use和assign之间依然有极小的一段真空期 ,有可能变量会被其他线程读取,导致 写丢失一次 ...o( ﹏ )o
  但是无论在哪一个时间点主内存的变量和任一工作内存的变量的值都是相等的。这个特性就导致了volatile变量不适合参与到依赖当前值的运算,如i = i + 1; i++;之类的那么依靠可见性的特点volatile可以用在哪些地方呢? 通常volatile用做保存某个状态的boolean值or int值。
  《深入理解Java虚拟机》提到:
  3、禁止指令重排概述
  指令重排序是指编译器或CPU为了优化程序的执行性能而对指令进行重新排序的一种手段,重排序会带来可见性问题,所以在多线程开发中必须要关注并规避重排序。
  从源代码到最终运行的指令,会经过如下两个阶段的重排序。
  第一阶段,编译器重排序,就是在编译过程中,编译器根据上下文分析对指令进行重排序,目的是减少CPU和内存的交互,重排序之后尽可能保证CPU从寄存器或缓存行中读取数据。从CPU层面来说,避免了处理器每次都去内存中加载stop,减少了处理器和内存的交互开销。
  第二阶段,处理器重排序,处理器重排序分为两个部分。
  并行指令集重排序,这是处理器优化的一种,处理器可以改变指令的执行顺序。
  内存系统重排序,这是处理器引入Store Buffer缓冲区延时写入产生的指令执行顺序不一致的问题。volatile有关的禁止指令重排的行为
  四大屏障的插入情况
  代码模拟
  模拟一个单线程,什么顺序读?什么顺序写?public class  VolatileTest {      int  i  =  0 ;      volatile boolean  flag  =  false ;      public void  write(){          i  =  2 ;          flag  =  true ;     }      public void  read(){          if ( flag ){             System. out .println( "---i = "  +  i );         }     } }
  在每一个volatile写操作前面插入一个StoreStore屏障 在每一个volatile写操作后面插入一个StoreLoad屏障 在每一个volatile读操作后面插入一个LoadLoad屏障 在每一个volatile读操作后面插入一个LoadStore屏障

战友美文美拍陶俊峰老照片回放系列5泰国风情战友美文美拍泰国风情,异域东南亚风光哈笑玫瑰作揖我(郭磊)在此先谢过陶老谢谢1970年就是新华社军事记者的陶老,又贡献出宝藏啦赞玫瑰笑作揖陶俊峰当年在曼谷留影陶俊峰书写泰国风情图文糖尿病早上起来有这3种情况请抓紧看医生小便有泡沫出现尿泡沫的问题可大可小,比较轻的,可能是尿道或者肾脏内有一些炎性反应导致的严重的,就有可能是出现了肾脏方面的损伤。因为长时间的血糖高会导致肾小球毛细血管受损,造成肾小球2022年7月910日云南省部分风景区天气预报云南省气象服务中心今天发布的未来24小时省内风景区天气预报晋宁郑和公园,小雨转多云,1726度西双版纳望天树风景区,阵雨转小雨,2434度怒江大峡谷,中雨转多云,2536度宁洱那柯新能源汽车行业研究及中期策略持续进击,掘金新周期(报告出品方作者华鑫证券,尹斌,黎江涛)12022H1呈现V型走势,向好可期截止2022年7月4日收盘,申万电力设备下跌4。7,在全市场31个申万行业中处于第13位,领先沪深300昔日化工集聚区变身城市绿肺航拍城市绿心森林公园,碧水蓝天,林草葱茏,美不胜收。(马文晓摄)清晨,众鸟高飞,美好的一天被唤醒下午,蛙叫蝉鸣,展现着夏日的勃勃生机夜晚,月光星光和动物们相伴。这里,就是坐落于通州城市文化地探城工具品城指南作者秦兰珺五一小长假即将到来。无论我们宅在家里云游,还是在条件允许的情况下用双脚丈量我们的城市,文化地图都是一个不错的探城工具和品城指南。100多年前,国外的城市社会学家开始将地图滴普科技品牌焕新升级数据智能连接世界滴普科技自2018年创立,四年耕耘,一路见证并深入参与着数据智能行业的发展,开放创新百家争鸣。我们不断迭代技术打磨产品提升服务,领衔行业的口碑是我们点滴努力的印证。2022年,伴随7月致自己,夏天发朋友圈说说,让自己胸怀广阔大格局的励志句子高质量5万条经典文案资料库,关注我,让发朋友圈配文案,写动态,写心情,上热门更简单。如果有那句话触动你,就复制下来,粘贴到评论区,释放你的心声吧,任何尝试勇敢迈出第一步都是艰难的,李小冉和徐佳宁,做了16年朋友后再做夫妻,如今婚姻状况如何了?2014年6月,李小冉突然与相识多年的男闺蜜徐佳宁领证结婚了。彼时,她与前男友鄢颇才刚刚曝出分手,所以外界对她的闪婚都感到十分意外。媒体在惊诧的同时,也都把镜头对准了鄢颇。这位曾因朋友圈正能量励志图片早安心语今天的努力,决定你明天的实力生活再糟,也不妨碍你越来越好,要坚定要勇敢!周末,早上好!只要眼里装着繁华,管他春夏秋冬,心里如能守住清雅,就无惧窗间过马。只要目有所望,心有所想,叶落不美也诗意,花落无声也优雅。104岁东方居里夫人王明贞养生秘诀6大习惯,活过百年1hr多用脑。她是清华第一位女教授,她是第一位女物理学家,她是出类拔萃的科学家,她被誉为东方居里夫人,获奖无数,成绩卓越。她就是王明贞。她享年104岁,理所当然的寿星级别。众所周知
美俄宇航员乘坐俄联盟飞船返回地球美俄宇航员乘坐俄联盟飞船返回地球新华网3月30日,在哈萨克斯坦杰兹卡兹甘附近,美国宇航员马克范德海(左)俄罗斯宇航员彼得杜布罗夫(右)和安东什卡普列罗夫与工作人员合影。3月30日,油价调整消息今天4月1日,调整后全国9295号汽油零售限价新一轮油价调整已在今天凌晨开启,由于前一天国际原油上涨逾3,预期的压线上调并没有出现,最终汽柴油价格每吨均上调110元,又是一次单曲循环式的油价调整,因为进入今年以来的6次油价调整三星小公主李元珠背靠千亿闺蜜团,竟因一张自拍被网暴?(一)想必大家都知道三星在韩国是什么样的地位吧?作为韩国最大的财阀集团,没有之一,三星在所有韩国人眼里都是神一般的存在。可就是影响力如此巨大的财团,他们的小千金竟然因为一张照片而被油价调整消息今天3月31日,全国加油站调整后9295汽油新售价今日油价最新调整消息今天3月31日,星期四,今日国际油价(欧佩克wti原油)大幅上涨截至当日收盘时,美国WTI5月原油期货电子盘价格周四(3月31日)收盘上涨3。58美元,涨幅3。重大Nature大子刊首次试验证实晶体所有晶界均存在过热现象导读由于直接实验测试的难度,晶界(GBs)是否预熔是一个长期存在的问题。本文采用聚焦光束以局部加热块状硬球胶体晶体中的单个晶界,通过视频显微镜观察单粒子分辨率下的熔化动力学。我们发临近保质期的进口婴幼儿配方奶粉,国家不让进口,你也最好不要买据报道,日前,天津东疆海关查获一批临期进口婴儿配方乳粉,共计27。37吨,现已移交后续处置。由于该批进口婴幼儿配方乳粉的申报日期到保质期截止日不足3个月,根据关于进一步加强婴幼儿配刘晏含机车风又帅又飒,已无望空降国家队,或可担任二队队长近日,刘晏含也跟风更新了一则动态,单手抱起了自己的好友,文案则是写道想挂起一米八八,首先你得有点弹跳。不过众人的关注点貌似都放在了刘晏含的装扮上,一身机车风的装扮,被不少球迷称赞为又一巨头破产?曾连续4年登世界500强,今负债1878亿2021年国际原油价格大幅上涨之际,中国一体化能源化工巨头中石化的经营业绩创近10年来的最佳水平。与此同时,面对全球疫情叠加地缘风险因素的影响,在邮轮市场低迷的背景下,国内运力规模宫下瑶重回国家队!日本女排公布39人集训名单,小幡真子意外落选在经历了家门口的惨败后,日本女排重振旗鼓,老帅真锅正义出山,取代女帅中田久美。3月31日,日本排协公布了新一届日本女排39人名单,小幡真子石井优希黑后爱等名将悉数落选,宫下遥重回国3月31日要闻回顾商务部目前中美双方经贸团队保持正常沟通国家开展年内第三批中央冻猪肉储备收储工作商务部目前中美双方经贸团队保持正常沟通商务部新闻发言人束珏婷3月31日在发布会上表示,中美拥有巨大的共同利益,合作是唯一正确的选择。希望美方采取理性务实的对华经贸政策,与中方相向而出国劳务不知道选哪国?来看看选择较多的两个国家想出国劳务的朋友们,第一步遇到的问题就是去哪个国家,想出国却一直在犹豫选哪个国家好?不知道哪个国家薪资高,担心社会治安好不好?下面的两个国家一直是被选择较多的国家,来看看适不适合你