volatile关键字

   在学习什么是volatile之前,首先应该认识一下Java内存模型。Java中的内存模型如图所示:
这里写图片描述
   主内存:Java内存模型规定了所有的变量都存储在主内存中。主内存被所有的线程所共享。

   工作内存:每条线程中都有自己的工作内存。
可以简单滴理解为计算机中的CPU高速缓存,但又不完全相同。线程的工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来),相当于“副本”。线程对变量的所有操作(读取,赋值)都必须在工作内存中进行。

   不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。

   那么为什么不在主内存上进行直接的操作呢?让我们一起来看一个例子:

   假设有这样一个静态变量:

static int i = 0;

   线程A执行如下代码:

i = 1;

   那么Java内存模型工作流程如下:

   首先主内存中i=0;线程A把静态变量i=0从主内存读到工作内存;然后再执行i=1操作,最后再把i=1 这个结果同步更新到主内存中。对于单线程来说,这个过程没有任何问题。

   此时,我们引入线程B,执行如下操作:

 System.out.println("i = " + i);

   如果线程A先执行,线程B后执行,线程B的输出结果会是什么呢?有两种可能,是1或者0。

   更大的可能是i=1;修改成功,原理很简单不再赘述。我们来看下另外一种i=0的可能。

   首先,主内存中i=0;线程A把静态变量i=0从主内存读到工作内存;然后再执行i=1操作,因为工作内存所更新的变量并不会立即同步到主内存,所以虽然线程A在工作内存当中已经把变量i更新为1,但是线程B从主内存中获取的仍然是0,从而得到一个没有立即同步更新的结果 i=0。

   那么这种问题如何解决呢?关键字volatile就可以很好地解决这个问题。Java提供了volatile关键字来保证可见性。当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主内存中,当有其他线程需要读取时,它会去主内存中读取新值。为什么volatile关键字可以有这样的特性?这主要受益于java语言的先行发生原则(happens-before),即不需要通过任何手段就能够得到保证的有序性。

   在上述例子中,如果在静态变量i之前加上volatile修饰符,就不会产生i=0的结果了:

volatile static int i = 0;

   线程A、B依旧进行上个例子的操作,这样得到的结果一定就是i=1。

   但是,volatile只能保证共享变量的可见性,不能保证变量的原子性。并且,一旦一个共享变量被volatile修饰了之后,禁止指令重排序。

   小结:volatile除了保证可见性和阻止指令重排,但是不能保证原子性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值