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

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屏障

西安高科集团张小宁接任董事长祝杜宁接任总经理观点网讯6月15日,西安高科集团有限公司发布关于董事长总经理变更的公告。观点新媒体了解到,公司原董事长法定代表人贾长顺卸任,张小宁接任董事长原总经理杜万坤卸任,祝杜宁接任总经理。新墨西哥发生世纪大劫案劫匪不费一枪一弹抢走20箱金银据西班牙国家报网站6月13日报道,没有人被捕,没有发射一颗子弹,劫匪花了至少8个小时才得手。墨西哥最大的商业港口曼萨尼约历史上最大的抢劫案就像是一部悬疑小说的情节。当局证实,一个武全球油价疯涨,美国暗地里却乐开了花!拜登打的是什么算盘?时间进入夏天,国内的油价仍然是在疯涨,根本没有一丝一毫要停下来的迹象。最近国家发改委又发布消息说,自6月14日起,国内汽油柴油价格每吨都要提高390到375元。大家可以扳着手指算算51岁性感女神邱淑贞近照曝光,性感半辈子的她如今丰满又优雅说起上个世纪的众多港星,相信很多网友和观众都对其非常喜爱,其中性感女神邱淑贞更是获得了众多粉丝的青睐,天使的面孔,魔鬼的身材,古灵精怪的性格更是让粉丝喜爱,那时候的邱淑贞更是深受导战至巅峰特辑丨黄明昊段位一骑绝尘,杨幂排第三,张大大辅助后羿战至巅峰是一场一王者荣耀为背景,邀请了众多明星参与的综艺节目,现在已经在腾讯视频热播,而在这档节目中,明星选手也或多或少暴露了自己的游戏水平,下面一起来看看他们到底在哪个段位吧。大台湾海峡主权在我大陆强势宣示据香港中评社快评指出,外交部发言人汪文斌13日指出,中国对台湾海峡享有主权主权权利和管辖权,同时也尊重其他国家在相关海域的合法权利。此外,国际海洋法上根本没有国际水域一说,有关国家越线就打,西沙对峙47小时,052D以一敌三不惜一战强势退敌随着美国将亚太区域视为后院,带着一帮小弟时不时来搞点事情,大量舰机以自由航行或自由飞行为借口,不断在中国周边海空试探性踩红线。面对来势汹汹的欧美舰机,解放军一改过去较为温柔的警告驱钓鱼执法被反杀,公职人员戴10多万劳力士,工资够买吗?我就想抽根烟你不让我抽,我办你,一会儿让你认识认识我。哈尔滨一男子坐网约车抽烟被拒后,便以司机无证驾驶为由举报,随即来了几名没穿工装的壮汉。司机随即拍下视频曝光自己遭到钓鱼执法,9乌克兰正在流血波华资讯6月15日报道正在秘密讨论向乌克兰运送这些武器。让我们记住,支持乌克兰与冲突升级的威胁之间只有一线之隔。这些都是艰难的决定。这场战争实际上是北约和俄罗斯之间的战争,只是战场灵魂摆渡那些妖魔鬼怪作恶无数却能全身而退,凭什么?什么是正?什么是邪?什么是善?什么是恶?在我们的潜意识里,邪不能胜正,善良必将打败邪恶,可现实之中,真的如此吗?在西游记中,孙悟空决战一众妖魔之时,尚且要看看对战的妖精有没有后台,又一个亚速钢铁厂?卢甘斯克方面乌军扣押了约1000名平民作为人质(观察者网讯)随着与乌控地区连接的三座桥梁被全部摧毁,北顿涅茨克战局逐渐清晰。目前,残余乌军部队已被俄军逼退到市郊工业区,也就是亚速特化工厂(Azotplant)。卢甘斯克地区内政
为什么骡子怀孕必死?马和驴杂交生出骡子后,1910年苏联的生物专家伊诺万夫提出黑猩猩和人杂交计划,试图打造一只强大的半人半猿部队,这样就可以在欧洲有更大优势。这些半兽人反应虽然没有人类那么灵活,但是它产后生完宝宝,喂完奶后胸部松散下垂,怎么办?在哺乳期哺乳文胸穿上,乳房上方有个悬韧带,穿文胸保护悬韧带,悬韧带就想皮筋一样,皮筋弹力没有了,乳腺就会下垂,乳腺下垂了是没发修复的,保护好乳腺在哺乳期开始。现在自己可以用在家做乳ns我玩了塞尔达还有奥德赛,还有什么推荐的吗?NS上好游戏很多如果你喜欢多人游戏可以玩马里奥派对,游戏也能线上联机,派对聚会首选游戏,玩了不吃亏如果你喜欢解密冒险的,可以选择路易吉鬼屋3,这款游戏虽然以恐怖为主题,却一点都不恐67岁的老女人爱上45岁的男人是一种什么样的心理?讲真,你提出来的问题,很有问题。首先,67岁的女人叫老女人,那67岁的男人你会叫他老男人妈?其次,67岁的女人爱上45岁的男人,在你看来,似乎心理有什么问题了。那如果性别反过来你又十年前就是世界首富!资产遍布全球,李嘉诚到底有多少隐形资产?李超人的资产,可以说是一个谜。李超人的明面资产是300亿美圆左右。其实,这仅仅是他全部资产的三分之一。据保守地估计,李超人的总资产应该在1000亿美圆左右。仅举一例,就足以说明李超如果房地产不再是社会经济的主角了,那么下一个主角会是谁?随着国家房住不炒政策的不断推进,房地产行业的热度的确是在逐渐下降,这也才应该是正常的状态。我觉得社会经济的主角应该是一直是制造业和创新产业,即那些有高科技含量的产业。创新才是经济社魔兽世界中,有哪些比较易刷易得的幻化?魔兽世界幻化魔兽世界中有四个甲种,再加上职业套装各不相同,所以在不说种族职业的情况下很难说清楚哪些幻化比较好耍,下面就分享两套个人角色比较易得的幻化,也是胖哥目前使用的幻化。板甲板为什么说三亚是看海的好地方?看海我就挑选三亚国内有海的地方很多,由北往南有大连秦皇岛北戴河青岛厦门深圳珠海北海直至三亚西沙等。但要说能在一个地方把海玩出花样来,三亚就是一个不二选择的地方,一是三亚的无敌海天美主场33输给了南安普顿?你提出这样的问题,说明你不经常看球,特别是对英超更不了解。在足球世界中,一支球队上一场战胜了一个强大的对手,紧接着又莫名奇妙地输给了一支弱旅。这种情况在欧州足球的顶级联赛中屡见不鲜老人戴助听器会影响听力吗?助听器本身是很好的医疗器械,虽然不能治愈耳聋,但完全可以纠正下降的听力,如同近视眼就戴眼镜来纠正视力一样。所以道理上,不会造成听力继续下降,相反,如果需要使用而不用助听器,只会加重双侧听损75双耳试听了助听器,但只想配一只,店员说我戴一只会造成听觉剥夺,真的吗?您好,双侧听损75,双耳试听了助听器,但只想配一只,店员说我戴一只会造成听觉剥夺,真的吗?原则上都是建议双耳验配的,如果长期单侧佩戴助听器,另一侧耳由于长期听不到或听不清声音,减少