生活工程体验信仰哲学精神
投稿投诉
精神世界
探索历史
哲学文学
艺术价值
信仰创造
境界审美
体验技术
技能工具
工程信息
医学生产
生活运用
操作能力

Java并发编程核心理论

7月11日 眸中星投稿
  并发编程是Java程序员最重要的技能之一,也是最难掌握的一种技能。它要求编程者对计算机最底层的运作原理有深刻的理解,同时要求编程者逻辑清晰、思维缜密,这样才能写出高效、安全、可靠的多线程并发程序。本系列会从线程间协调的方式(wait、notify、notifyAll)、Synchronized及Volatile的本质入手,详细解释JDK为我们提供的每种并发工具和底层实现机制。在此基础上,我们会进一步分析java。util。concurrent包的工具类,包括其使用方式、实现源码及其背后的原理。本文是该系列的第一篇文章,是这系列中最核心的理论部分,之后的文章都会以此为基础来分析和解释。
  一、共享性
  数据共享性是线程安全的主要原因之一。如果所有的数据只是在线程内有效,那就不存在线程安全性问题,这也是我们在编程的时候经常不需要考虑线程安全的主要原因之一。但是,在多线程编程中,数据共享是不可避免的。最典型的场景是数据库中的数据,为了保证数据的一致性,我们通常需要共享同一个数据库中数据,即使是在主从的情况下,访问的也同一份数据,主从只是为了访问的效率和数据安全,而对同一份数据做的副本。我们现在,通过一个简单的示例来演示多线程下共享数据导致的问题:
  代码段一:
  packagecom。paddx。test。
  publicclassShareData{
  publicstaticintcount0;
  publicstaticvoidmain(String〔〕args){
  finalShareDatadatanewShareData();
  for(inti0;i10;i){
  newThread(newRunnable(){
  Override
  publicvoidrun(){
  try{
  进入的时候暂停1毫秒,增加并发问题出现的几率
  Thread。sleep(1);
  }catch(InterruptedExceptione){
  e。printStackTrace();
  }
  for(intj0;j100;j){
  data。addCount();
  }
  System。out。print(count);
  }
  })。start();
  }
  try{
  主程序暂停3秒,以保证上面的程序执行完成
  Thread。sleep(3000);
  }catch(InterruptedExceptione){
  e。printStackTrace();
  }
  System。out。println(countcount);
  }
  publicvoidaddCount(){
  
  }
  }
  上述代码的目的是对count进行加一操作,执行1000次,不过这里是通过10个线程来实现的,每个线程执行100次,正常情况下,应该输出1000。不过,如果你运行上面的程序,你会发现结果却不是这样。下面是某次的执行结果(每次运行的结果不一定相同,有时候也可能获取到正确的结果):
  可以看出,对共享变量操作,在多线程环境下很容易出现各种意想不到的的结果。
  二、互斥性
  资源互斥是指同时只允许一个访问者对其进行访问,具有唯一性和排它性。我们通常允许多个线程同时对数据进行读操作,但同一时间内只允许一个线程对数据进行写操作。所以我们通常将锁分为共享锁和排它锁,也叫做读锁和写锁。如果资源不具有互斥性,即使是共享资源,我们也不需要担心线程安全。例如,对于不可变的数据共享,所有线程都只能对其进行读操作,所以不用考虑线程安全问题。但是对共享数据的写操作,一般就需要保证互斥性,上述例子中就是因为没有保证互斥性才导致数据的修改产生问题。Java中提供多种机制来保证互斥性,最简单的方式是使用Synchronized。现在我们在上面程序中加上Synchronized再执行:
  代码段二:
  packagecom。paddx。test。
  publicclassShareData{
  publicstaticintcount0;
  publicstaticvoidmain(String〔〕args){
  finalShareDatadatanewShareData();
  for(inti0;i10;i){
  newThread(newRunnable(){
  Override
  publicvoidrun(){
  try{
  进入的时候暂停1毫秒,增加并发问题出现的几率
  Thread。sleep(1);
  }catch(InterruptedExceptione){
  e。printStackTrace();
  }
  for(intj0;j100;j){
  data。addCount();
  }
  System。out。print(count);
  }
  })。start();
  }
  try{
  主程序暂停3秒,以保证上面的程序执行完成
  Thread。sleep(3000);
  }catch(InterruptedExceptione){
  e。printStackTrace();
  }
  System。out。println(countcount);
  }
  增加synchronized关键字
  publicsynchronizedvoidaddCount(){
  
  }
  }
  现在再执行上述代码,会发现无论执行多少次,返回的最终结果都是1000。
  三、原子性
  原子性就是指对数据的操作是一个独立的、不可分割的整体。换句话说,就是一次操作,是一个连续不可中断的过程,数据不会执行的一半的时候被其他线程所修改。保证原子性的最简单方式是操作系统指令,就是说如果一次操作对应一条操作系统指令,这样肯定可以能保证原子性。但是很多操作不能通过一条指令就完成。例如,对long类型的运算,很多系统就需要分成多条指令分别对高位和低位进行操作才能完成。还比如,我们经常使用的整数i的操作,其实需要分成三个步骤:(1)读取整数i的值;(2)对i进行加一操作;(3)将结果写回内存。这个过程在多线程下就可能出现如下现象:
  这也是代码段一执行的结果为什么不正确的原因。对于这种组合操作,要保证原子性,最常见的方式是加锁,如Java中的Synchronized或Lock都可以实现,代码段二就是通过Synchronized实现的。除了锁以外,还有一种方式就是CAS(CompareAndSwap),即修改数据之前先比较与之前读取到的值是否一致,如果一致,则进行修改,如果不一致则重新执行,这也是乐观锁的实现原理。不过CAS在某些场景下不一定有效,比如另一线程先修改了某个值,然后再改回原来值,这种情况下,CAS是无法判断的。
  四、可见性
  要理解可见性,需要先对JVM的内存模型有一定的了解,JVM的内存模型与操作系统类似,如图所示:
  从这个图中我们可以看出,每个线程都有一个自己的工作内存(相当于CPU高级缓冲区,这么做的目的还是在于进一步缩小存储系统与CPU之间速度的差异,提高性能),对于共享变量,线程每次读取的是工作内存享变量的副本,写入的时候也直接修改工作内存中副本的值,然后在某个时间点上再将工作内存与主内存中的值进行同步。这样导致的问题是,如果线程1对某个变量进行了修改,线程2却有可能看不到线程1对共享变量所做的修改。通过下面这段程序我们可以演示一下不可见的问题:
  packagecom。paddx。test。
  publicclassVisibilityTest{
  
  
  privatestaticclassReaderThreadextendsThread{
  publicvoidrun(){
  try{
  Thread。sleep(10);
  }catch(InterruptedExceptione){
  e。printStackTrace();
  }
  if(!ready){
  System。out。println(ready);
  }
  System。out。println(number);
  }
  }
  privatestaticclassWriterThreadextendsThread{
  publicvoidrun(){
  try{
  Thread。sleep(10);
  }catch(InterruptedExceptione){
  e。printStackTrace();
  }
  number100;
  
  }
  }
  publicstaticvoidmain(String〔〕args){
  newWriterThread()。start();
  newReaderThread()。start();
  }
  }
  从直观上理解,这段程序应该只会输出100,ready的值是不会打印出来的。实际上,如果多次执行上面代码的话,可能会出现多种不同的结果,下面是我运行出来的某两次的结果:
  当然,这个结果也只能说是有可能是可见性造成的,当写线程(WriterThread)设置readytrue后,读线程(ReaderThread)看不到修改后的结果,所以会打印false,对于第二个结果,也就是执行if(!ready)时还没有读取到写线程的结果,但执行System。out。println(ready)时读取到了写线程执行的结果。不过,这个结果也有可能是线程的交替执行所造成的。Java中可通过Synchronized或Volatile来保证可见性,具体细节会在后续的文章中分析。
  五、有序性
  为了提高性能,编译器和处理器可能会对指令做重排序。重排序可以分为三种:
  (1)编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  (2)指令级并行的重排序。现代处理器采用了指令级并行技术(InstructionLevelParallelism,ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
  (3)内存系统的重排序。由于处理器使用缓存和读写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
  我们可以直接参考一下JSR133中对重排序问题的描述:
  (1)(2)
  先看上图中的(1)源码部分,从源码来看,要么指令1先执行要么指令3先执行。如果指令1先执行,r2不应该能看到指令4中写入的值。如果指令3先执行,r1不应该能看到指令2写的值。但是运行结果却可能出现r22,r11的情况,这就是重排序导致的结果。上图(2)即是一种可能出现的合法的编译结果,编译后,指令1和指令2的顺序可能就互换了。因此,才会出现r22,r11的结果。Java中也可通过Synchronized或Volatile来保证顺序性。
  六总结
  本文对Java并发编程中的理论基础进行了讲解,有些东西在后续的分析中还会做更详细的讨论,如可见性、顺序性等。后续的文章都会以本章内容作为理论基础来讨论。如果大家能够很好的理解上述内容,相信无论是去理解其他并发编程的文章还是在平时的并发编程的工作中,都能够对大家有很好的帮助。
投诉 评论

穿出旗袍的优雅气质,你需要知道这些旗袍仪态,一生的气质与自信西方趋向个性审美,崇尚立体的个性,东方趋向传统的审美,崇尚柔和的共性。如果说西方女性像钻石,明亮耀眼;东方女性则像珍珠,圆润朦胧;如果说西方女性像皮革,刚强挺阔;东方女性则像丝……你有发现过什么新大陆吗?在高德地图上发现了一个好地方。还是去年的时候,去农村亲戚家里做客,返回的时候经过了一个海边的度假酒店,在里面玩了一会儿。禁止转载还有一个小亭子,不收费。于是我……Java并发编程核心理论并发编程是Java程序员最重要的技能之一,也是最难掌握的一种技能。它要求编程者对计算机最底层的运作原理有深刻的理解,同时要求编程者逻辑清晰、思维缜密,这样才能写出高效、安全、可……我的世界java版还是基岩版?小孩子才做选择很久以前,你刚开始玩《我的世界》的时候,玩的是java版还是基岩版?还记得当时的游戏是什么样的吗?方块菌当时是两个版本都玩了上次方块菌分享了一些java版已经消失的……东野圭吾笔下人间清醒的句子2021生机大会01。要选择这个就要舍弃那个,如此反复,这就是人生。《信》02。放弃不难,但坚持一定很酷。《解忧杂货店》03。世上有两样东西不可直……广东前锋曾远赴海外打球追梦,对阵广厦得0分!命中率0昨天广东队以86:98,输给广厦队。数据方面:广厦队:胡金秋23分9篮板3抢断2封盖,赵岩昊30分3篮板2助攻3抢断,琼斯17分9篮板3助攻2抢断,朱俊龙10分3篮板3抢……广厦男篮坏消息,超级外援签证被拒,第二阶段基本确定全华班CBA窗口期已经过去了一半,各队的外援情况已经大体明确。除了江苏男篮依旧没有外援消息外,其他19支球队都已经有了明确的外援人选。不过由于目前的特殊情况,在签证办理方面有些严格,……互联网的寒冬要来了吗?伴着窗外的夜色,开一点窗子,吹一缝夜风,喝上一口冰凉的白开水,又到了一天中最为放松的时刻。坐在键盘前,和读者朋友聊聊天吧。人啊,就不可预料,自己的命运和环境的变迁有……傲世龙城神器版兵魂品阶介绍傲世龙城兵魂品阶如何升级?哈喽大家好!我是你们爱玩传奇的小芙,相信大家在傲世龙城中都拥有一个属于自己的趁手兵魂吧,那么兵魂应该如何升阶呢?兵魂升阶又需要什么材料呢?一起来看看吧!转自卫星muaa5……秋冬秀场,绕不开风超大的Celine2022fw啦!好想这么Hello姐妹们好啊!继上次唠过复古精致的CHANEL秀场之后,秀场系列今儿又来更新啦说到秋冬秀场,一定绕不开风超大的CELINE2022FW啦!毕竟在我心里……幻塔虚空裂隙之boss希尔心得作者:NGA业火大侠前排提示,不同服务器的boss并不一样,加成也不一样。希尔是班吉斯3的boss,加成为冰雷抗(受到的冰雷伤害减半)、极寒(周围玩家移动速度减少百……来自离异家庭的内马尔,为什么性格那么好?头条创作挑战赛认识内马尔的人都知道,他跟谁感觉都挺开心的,整天傻嘻嘻笑呵呵的像个孩子,要知道他已经30岁了,而且个人认为他是那种直来直去情绪来得快去得也快的人,还不怎么记仇,走……
软银研发出以无人机探测灾害被埋者手机信号的技术乌鲁木齐大火,通报需要悲悯威利格林灰熊的对抗强度很棒,亚当斯一人就抢了21个篮板61分11板10助!CBA超外创纪录一战打满全场逆转同曦,拿CBA三消息广东队长全新人选,林书豪离开赛区,福建鱼腩战输球埃梅卡在非洲的许多地方,太阳能已逐步成为买得起而又清洁环保的潮流转瞬即逝,沉淀下来的都是闪光点专访军品古着收藏家大飞阳了之后,这样吃会好受点外卖小哥冬天怕顶不住,专门找中医调理手脚怕冷的毛病NBA上脚!欧文改穿杜兰特战靴!Ja1再曝新配色!1月新剧,刘亦菲李现扮欢喜冤家,我对靳东宋佳新剧情有独钟13连胜,直冲联赛第1,CBA昔日霸主重新崛起,辽宁卫冕难了家长请听好孩子不是我们的装饰品咱当兵的人校园四季风光视觉鲜明沙宣头发型透亮细致给你多元化的气质有人说宇宙是无限的可有人却不这么认为江少川教授领衔绘制湖北作家世界地图猕猴桃排毒祛斑功效一流旅游精品线路写方案时该如何高效表达创意,才能不被Pass掉?不一样的三年级之角色在银行办理业务时摔伤怎么办孩子怕人如何应对心理健康

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找