从Java多线程可见性谈HappensBefore原则.docxVIP

从Java多线程可见性谈HappensBefore原则.docx

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
从Java多线程可见性谈Happens-Before准绳 在现代操作系统上编写并发程序时,除了要留意线程平安性(多个线程互斥访问临界资源)以外,还要留意多线程对共享变量的可见性,而后者往往简约被人忽视。 可见性是指当一个线程修改了共享变量的值,其它线程能够适时得知这个修改。在单线程环境中,假如在程序前面修改了某个变量的值,后面的程序肯定会读取到那个变量的新值。这看起来很自然,然而当变量的写操作和读操作在不同的线程中时,情况却并非如此。 public class NoVisibility { private static boolean ready; private static int number; private static class ReaderThread extends Thread { public void run() { while(!ready) { Thread.yield(); } System.out.println(number); } } public static void main(String[] args) { new ReaderThread().start(); //启动一个线程 number = 42; ready = true; } } 上面的代码中,主线程和读线程都访问共享变量ready和number。程序看起来会输出42,但现实上很可能会输出0,或者根本无法终止。这是由于上面的程序缺少线程间变量可见性的保证,所以在主线程中写入的变量值,可能无法被读线程感知到。 为什么会消灭线程可见性问题 要想解释为什么会消灭线程可见性问题,需要从计算机处理器结构谈起。我们都晓得计算机运算任务需要CPU和内存相互协作共同完成,其中CPU担任规律计算,内存担任数据存储。CPU要与内存进行交互,如读取运算数据、存储运算结果等。由于内存和CPU的计算速度有几个数量级的差距,为了提高CPU的利用率,现代处理器结构都加入了一层读写速度尽可能接近CPU运算速度的高速缓存来作为内存与CPU之间的缓冲:将运算需要使用的数据复制到缓存中,让CPU运算可以快速进行,计算结束后再将计算结果从缓存同步到主内存中,这样处理器就无须等待缓慢的内存读写了。 高速缓存的引入处理了CPU和内存之间速度的冲突,但是在多CPU系统中也带来了新的问题:缓存全都性。在多CPU系统中,每个CPU都有本人的高速缓存,全部的CPU又共享同一个主内存。假如多个CPU的运算任务都涉及到主内存中同一个变量时,那同步回主内存时以哪个CPU的缓存数据为准呢?这就需要各个CPU在数据读写时都遵照同一个协议进行操作。 参考上图,假设有两个线程A、B分别在两个不同的CPU上运转,它们共享同一个变量X。假如线程A对X进行修改后,并没有将X更新后的结果同步到主内存,则变量X的修改对B线程是不行见的。所以CPU与内存之间的高速缓存就是导致线程可见性问题的一个缘由。 CPU和主内存之间的高速缓存还会导致另一个问题——重排序。假设A、B两个线程共享两个变量X、Y,A和B分别在不同的CPU上运转。在A中先更转变量X的值,然后再更转变量Y的值。这时有可能发生Y的值被同步回主内存,而X的值没有同步回主内存的情况,此时对于B线程来说是无法感知到X变量被修改的,或者可以认为对于B线程来说,Y变量的修改被重排序到了X变量修改的前面。上面的程序NoVisibility类中有可能输出0就是这种情况,虽然在主线程中是先修改number变量,再修改ready变量,但对于读线程来说,ready变量的修改有可能被重排序到number变量修改之前。 此外,为了提高程序的执行效率,编译器在生成指令序列时和CPU执行指令序列时,都有可能对指令进行重排序。Java言语规范要求JVM只在单个线程内部维护一品种似串行的语义,即只需程序的最终结果与严格串行环境中执行的结果相同即可。所以在单线程环境中,我们无法察觉到重排序,由于程序重排序后的执行结果与严格按挨次执行的结果相同。就像在类NoVisibility的主线程中,先修改ready变量还是先修改number变量对于主线程本人的执行结果是没有影响的,但是假如number变量和ready变量的修改发生重排序,对读线程是有影响的。所以在编写并发程序时,我们肯定要留意重排序对多线程执行结果的影响。 看到这里大家肯定会发觉,我们所争辩的CPU高速缓存、指令重排序等内容都是计算机体系结构方面的东西,并不是Java

文档评论(0)

bob157641554 + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档