`
爱上这个世界
  • 浏览: 257 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

一段停不下来的程序所想到的

 
阅读更多

今天在准备分享内存可见性问题时的keynote时写了一个demo程序,却产生了很多启发性的问题。先来看看程序



 
这个程序的逻辑很简单,就是50个线程做累加,然后算个总数。主线程自旋等待所有子线程结束。但这个程序在我的 电脑上是停不下来的,但在其它同事的电脑上却能停的下来。我的第一反应是,AddThread的finish变量不是volatile的,是不是因为这个可见性问题导致程序停不下来呢?果然,把finish改成volatile程序停下来了,这是大家都知道的知识,volatile在不同的vm上和不同的cpu上表现是不一样的。
但是实验没有停止,我把add前面的synchronized去掉了,程序奇迹般的停下来了,虽然最后结果不对(缺乏正确同步),这又是为什么呢?仔细想来可能是不加synchronized执行的快一些把,可能主线程进while循环的时候,子线程都已经搞完了。这时候去加载finish变量的时候,由于是第一次读取,肯定要去主存读得。。所以应该能拿到正确的值。为了验证这个结果,去掉synchronize,在addThread里面加入一个sleep,让它跑得慢一点。sleep(1),停下了。。sleep(10),停下了。。sleep(100),程序奇迹般的停不下了。所以这个推测是正确的。也就是说如果进了while循环,子线程都跑完了,程序是能正常结束的。但是子线程没跑完,就结束不了了。合理的解释是第一次读取变量和刷新变量的逻辑还是不一样的
另外还有种让程序停止的方法,就是在else里面让cpu稍微干点活。这个活,必须是费cache的。复杂的运算不行,必须要让cpu的cache失效。可以是一个io操作,如System.out.println   (因为这时候cpu会从us状态切换到sy状态,从而让缓存失效)。或者分配一个大数组。我尝试分配了一个长度为1000的数组,程序没有停下,但分配10000,程序停下了。。也就是说我cpu的每个核心自由的cache,应该也就是在几k这个数量级了。。这时候cpu cache失效,会重新加载finish变量。。程序就停下了
最后有一点,count.get()程序能正常结束的情况下,总是能正确输出5000000,我的猜想是,程序读到了finish的值,应该也能读到int的值了。只要让缓存失效,重新加载finish,那么int字段应该也是重新加载的了。所以就算没有用显示的同步,依然可以拿到正确的结果

 

  • 大小: 154.5 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics