java中的volatile关键字

 使用volatile关键字时,会有很多误用volatile修饰的变量只是保证对线程的可见性,被volatile修饰的变量被修改时,被强制写入内存,所以其他的线程保证得到的变量值是最新的。现在我们看看我们疑惑的代码:

如以下代码:

 

<span style="font-size:14px;">public class Test { </span>
<span style="font-size:14px;">	volatile static int x = 0; </span>
<span style="font-size:14px;">	public static void main(String[] args) {	</span>
<span style="font-size:14px;"><span style="white-space:pre">		</span> for (int i = 0; i < 1000; i++) {	</span>
<span style="font-size:14px;"><span style="white-space:pre">			</span> new Thread(new Runnable() { 	</span>
<span style="font-size:14px;"><span style="white-space:pre">			</span> @Override	 </span>
<span style="font-size:14px;"><span style="white-space:pre">				</span>public void run() { </span>
<span style="font-size:14px;"><span style="white-space:pre">					</span>Test.add(); 	 }	</span>
<span style="font-size:14px;"><span style="white-space:pre">			</span> }).start();	</span>
<span style="font-size:14px;"><span style="white-space:pre">		</span> }	</span>
<span style="font-size:14px;"><span style="white-space:pre">		</span> System.out.println(x);	</span>
<span style="font-size:14px;"><span style="white-space:pre">	</span>} 	</span>
<span style="font-size:14px;"><span style="white-space:pre">	</span>public static void add() {	 x++;	}</span>
<span style="font-size:14px;">}</span>


结果并不像我们想的会输出1000,而是输出了997;

 

我们来分析一下原因:

 

多线程并发时,虚拟机会为每一个线程创建一个自己的线程栈,线程栈保存了变量运行时的信息。

然后线程在运行时会找到变量的信息并且加载到自己的线程栈中,在栈中复制一份变量的副本,接着线程在运行时就不再访问堆中的变量,而是直接修改访问自己的线程栈中的变量。

有些人就会问既然volatile修饰的变量对线程可见,就说明每一次自增运算以后x都被强制写入内存中,说明下一个线程进行读操作时x发生改变,就可以进行正确的自增,那为什么上面的程序没有输出1000

 

这是因为volatile虽然可以保证所有线程可见,但它不能保证操作的原子性:

 

怎样理解这句话呢?我们先来看看线程工作的流程图:



volatile可以保证在读操作时读到的值是最新的,现在考虑如下问题:

         如果现在x=0;线程1读完操作和加载操作已经完成,而这时cpu不执行x线程1,转而执行线程2cup调度时是以时间片来调度的),此时线程1还没有执行同步操作,因此没有写入主存,而线程2此时开始读主存,那一定读到的是x=0,此时县城2对变量操作,即x++,然后线程2中的x的变量副本变成了1cpu调度线程1继续执行,此时线程1执行到了对x++此时x在线程1中的变量副本的值为1

 

  所以线程1,和线程2x的值都进行了++操作,但是x的值只加了1

 这是因为volatile关键字不能保证线程操作的原子性。所以还是会出现并发不安全的现象。

 

 

 

 

 

参考:  http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html

                http://www.cnblogs.com/dolphin0520/p/3920373.html

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值