volatile小记

1、要使volatile变量提供理想的线程安全,必须同时知足如下两个条件:
1)、对变量的写操做不依赖于当前值;
2)、该变量没有包含在具备其余变量的不变式中。

第一个条件的限制使volatile变量不能用做线程安全的计数器。虽然增了操做(x++)看上去相似一个单独操做,实际上它是一个由读取-修改-写入操做序列组成的组合操做,必须以原子方式执行,而volatile不能提供必须的原子特性。实现正确的操做须要使x的值在操做期间保持不变,而volatile变量没法实现这一点。


2、通常共享变量是存放中主内存中,每个线程都有一个属于本身的工做内存;当一个线程开始时,会将变量从主内存中拷贝一份副本放在本身的工做内存中,当使用时就高效多了,当有更改时,会回写到主内存中;当此时有多个线程对同一个共享变量进行操做时,只会操做属于本身线程的工做内存,以后回写到主内存中,相互之间不会有影响,故此时会有多线程安全问题。当该共享变量使用volatile修改时,一个线程对其进行了修改,则其回写到主内存时,会告知其余有该共享变量的副本,该副本已经失效了,故其余线程要使用该共享变量时,就会从新从主内存中拷贝一份副本到本线程中,以确保其线程内使用的都是最新的。

三、通常一个线程对变量的操做须要经历从主内存中读取Read--->加载到工做线程中load---->在工做线程中使用use--->该该共享变量进行赋值asign--->对该共享变量进行存储store--->将该共享变量回写到主内存中write。


4、一个共享变量被volatile修饰以后,就具有两层含义:
1)、保证不一样线程对这个变量进行操做时的可见性,即一个线程修改了变量的值,该变量的新值对其余线程来讲是当即可见的,但不保证操做的原子性;
2)、禁止进行指令重排。

5、使用synchronized能够保证变量修改的可见性和原子性,而volatile只能保证变量的可见性;synchronized是重量级的加锁,且开销大,而volatile是轻量级的无锁,且开销小

6、对于volatile修饰的引用类型(包括对象、数组等),其仅仅是保证引用地址的可见性,而不是引用指向的对象中元素的可见性。

7、通常64位的long和double是非原子操做的,是使用高低32位来进行赋值的,故这种64位的变量的赋值是非原子操做的,但在现代JVM中,都已保证该赋值操做是原子操做的。

8、关于指令重排,是指处理器为了提升处理速度将一些指令从新排序,但保证最终的结果是一致的,跟重排前的结果同样,这种是容许的;而volatile能防止指令重排,能够认为是在指令中增长了内存屏障,使在该volatile修饰的变量所属的指令,在没有使用以前,其前面的指令能够放在该指令以后,其后面的指令一样能够放在该指令以前,但有了该修改,则不会这样。


参考:
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
http://www.infoq.com/cn/articles/ftf-java-volatile
相关文章
相关标签/搜索