码迷,mamicode.com
首页 > 编程语言 > 详细

一个Java内存可见性问题的分析

时间:2016-07-30 13:37:39      阅读:154      评论:0      收藏:0      [点我收藏+]

标签:

如果熟悉Java并发编程的话,应该知道在多线程共享变量的情况下,存在内存可见性问题:

在一个线程中对某个变量进行赋值,在另外一个线程中读取该变量的值,读取到的可能仍然是以前的值;

这里并非说的是时序的问题,例如读取操作在赋值操作之前执行了,而是说,

即使在另外一个线程中循环读取该变量的值,也可能永远看不到变量的最新值,或者一段时间内看不到。

请看下面的代码片

 1 public class Main extends Thread {
 2     private static boolean flag = false;
 3     
 4     @Override
 5     public void run() {
 6         while (!flag);
 7     }
 8     
 9     public static void main(String[] args) {
10         Main m = new Main();
11         m.start();
12         try {
13             Thread.sleep(200);
14         } catch (InterruptedException e) {
15             e.printStackTrace();
16         }
17         flag = true;
18         try {
19             m.join();
20         } catch (InterruptedException e) {
21             e.printStackTrace();
22         }
23         System.out.println("done");
24     }
25 }

这段代码在Windows,Linux,MacOS下的HotSpot中运行都不能结束

将变量flag声明为volatile的话,程序可正常结束,

类似的程序在Android的dalvik下运行并没有问题

奇怪的是,如果增加一个print语句,它也可以正常结束。

如果查看字节码的话,发现除了flag变量的volatile标记之外,字节码并无不同

从这里我们可以推断,并非是字节码执行的问题,因此怀疑是JIT的缘故,关掉JIT,再次运行,果然就都正常了。

如果是JIT的话,生成了机器代码,按照CPU的缓存一致性协议,变量有可能短时间之内不可见,那也应该过一段时间就能可见了,计算机上同时运行着这么多程序,像store buffer这样的结构应该会不时被刷新到混存中,甚至内存中,应该不至于导致永远不可见。

那么到底是什么导致了永久不可见?不是字节码执行引擎,不是硬件问题,唯一可能的就是JIT生成的代码导致的了。

那么接下来就是查看JIT代码了:

一个Java内存可见性问题的分析

标签:

原文地址:http://www.cnblogs.com/frydsh/p/5720658.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!