`
milk_36
  • 浏览: 118248 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java的 volatile原来是这样?

阅读更多

前些日子在看些多线程方面的资料,当我看到对volatile这个关键字的解释的时候,让我出现了一些困惑!

 

在某些书籍中说

写道
'在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步.当你定义long或double变量时,如果使用volatile关键字,就会获得(简单的赋值与返回操作的 )原子性'
 

 然而一篇IBM技术论坛上的文章似乎又有不同的观点(http://www.ibm.com/developerworks/cn/java/j-jtp06197.html)

Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。

 两段文字粗略一看,似乎搞得人晕头转向了,更加难以理解volatile的特性了!

但是请注意第一段文字中被标红的一段"简单的赋值与返回操作的 原子性",这里似乎说明这种原子性不可靠!因为long和double类型的长度都是64位的,由于jvm的原因可能造成撕扯现象.这里的简单原子性应该是保证变量不会被撕扯得面目全非吧!

有人对Volatile做如下整理(http://hi.baidu.com/lifa868/blog/item/22bc7718926ad772dbb4bd0e.html):

写道
Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。

这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。

而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。

使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。

 

后来在一篇对C#中volatile相关文章中看到这样一句话(http://www.cnblogs.com/lucifer1982/archive/2008/03/23/1116981.html):

写道
到这里,我们已经知道volatile提供的同步机制还不足以能够实现线程安全计数器。因为计数器虽然简单,却是三种操作的组合,如果多线程试图进行增量操作,很可能会丢失其更新值。

 

还有这样一种理解,volatile在增量操作时已经失去了原子性,如i++其实是i=i+1,这种情况下我们就认为原子性将丢失。而在i=m的情况下是可以保证原子性的!

这样一来是不是可以做出以下理解:

   java中有主内存和工作内存之分,当变量变申明volatile之后.

1.所有的读写操作都直接从主内存进行.

2.每次对变量的修改强行回写到主内存中,供其他线程共享!

最后想做一个假设,以说明自己对上诉观点的理解:

static volatile int i=0;
static void add(){
    i++;
}
.......

在多线程并发访问add()方法的时候,T1线程和T2线程同时进入add(),由于{i++}=={i=i+1}其实是先从主内存中读取i,而后对i进行增量修改,最后回写主内存。那就有可能出现这样的情况:在T1进入后读取的i=9,T2同时也读取的也是9,T1线程操作后i=10然后回写主内存,T2也同时完成操作i=10也回写主内存,那T2的回写值是不是就覆盖了T1的回写值,这也就是上述中所提及的“如果多线程试图进行增量操作,很可能丢失其更新值”。

由于对jvm内存设计不是非常熟悉,不清楚实际jvm中对volatile是否在内存也是这样操作的,希望大家能提供更多资料以便相互交流,探讨!

分享到:
评论
2 楼 milk_36 2011-01-16  
gteam.yu 写道
我也来说说个人感觉,如果是单核的CPU,那么多线程执行实际上是分时间片的,所以LZ所说同时写成10的可能性好像没有吧,当T1将i写成10的时候,应为关键字volatile所以T2这个时候取到的i应该就是10不是9了 ;而在多核的环境中我们编写代码就应该用lock来让一个线程执行的时候另一个保持wait(),这个是个人的见解,如果不对的请大侠纠正,如果给出代码,小弟万分感谢。

volatile在网上也有很多讨论!你说的单核cpu情况下符合了Sequential Consistency模型,但在多核的情况下sc模型没有被严格执行.
1 楼 gteam.yu 2010-12-30  
我也来说说个人感觉,如果是单核的CPU,那么多线程执行实际上是分时间片的,所以LZ所说同时写成10的可能性好像没有吧,当T1将i写成10的时候,应为关键字volatile所以T2这个时候取到的i应该就是10不是9了 ;而在多核的环境中我们编写代码就应该用lock来让一个线程执行的时候另一个保持wait(),这个是个人的见解,如果不对的请大侠纠正,如果给出代码,小弟万分感谢。

相关推荐

Global site tag (gtag.js) - Google Analytics