volatile 关键字
译自 http://www.javamex.com/tutorials/synchronization_volatile.shtml
一、简介
volatile在JAVA5开始变化比较大。
volatile是用来说明变量的值会被多个线程修改到,用volatile关键字定义了的变量意味着:
1.这个变量的值不会被线程cache到,所有的读写操作都是直接操作主存
2.访问这个变量的操作就好象是在synchronized block中一样,synchronized(this object)。当然实际上是并没有lock的。
我们来比较一下synchronized和volatile
characteristic
|
synchronized
|
volatile
|
变量类型 |
对象 |
对象 或 基本类型(指int,long,float..) |
NULL适用么? |
否(会抛出NullPointerException) |
是 |
会阻塞么? |
是 |
否 |
All cached variables synchronized on access? Yes From Java 5 onwards
在访问的时候所有cache的变量都同步么? |
是 |
在JAVA5前/后? |
什么时候进行同步? |
在你明确地进入或离开一个synchronized块时 |
任何时候访问volatile变量 |
可以用来组合多个操作成为一个原子操作? |
是 |
在JAVA5之前不行,JAVA5之后可以 |
二、一个volatile的例子
volatiel一个典型的应用就是拿来做停止线程的flag变量
public class StoppableTask extends Thread {
private volatile boolean pleaseStop;
public void run() {
while (!pleaseStop) {
// do some stuff...
}
}
public void tellMeToStop() {
pleaseStop = true;
}
}
pleaseStop这个变量如果没有定义为volatile,那么线程很可能会把这个变量的值在loop开始的时候就cache在寄存器中,然后一直也不会再去读取,这是很危险的事情。
三、JAVA5中的volatile关键字
在JAVA5中,在访问volatile变量时,会create一个内存屏障(memory barrier),会在主存中同步所有这个变量的实例(synchronizes all cached copies of variables with main memory)。
read after write
先看一个经典的应用,Fixing Double-checked Locking(DCL)
在单例模式设计中,采用lazy initialisation
public class MyFactory {
private static MyFactory instance;
public static synchronized MyFactory getInstance() {
if (instance == null)
instance = new MyFactory();
return instance;
}
private MyFactory() {}
}
这种写法的缺点是 getInstance方法调用会比较慢,因为要同步,所以有些人会这样写来改进:
public class MyBrokenFactory {
private static MyFactory instance;
private int field1, field2 ...
public static MyBrokenFactory getFactory() {
// This is incorrect: don't do it at home, kids!
if (instance == null) {
synchronized (MyBrokenFactory.class) {
if (instance == null)
instance = new MyFactory();
}
}
return instance;
}
private MyBrokenFactory() {
field1 = ...
field2 = ...
}
}
但这样是有问题的:
Thread 1: 'gets in first' and starts creating instance. |
Thread 2: gets in just as Thread 1 has written the object reference to memory, but before it has written all the fields. |
1. Is instance null? Yes.
2. Synchronize on class.
3. Memory is allocated for instance.
4. Pointer to memory saved into instance.
7. Values for field1 and field2 are written
to memory allocated for object. |
5. Is instance null? No.
6. instance is non-null, but field1 and
field2 haven't yet been set!
This thread sees invalid values
for field1 and field2! |
解决办法,要么用synchronized,要么不要用lazy-initialization,直接构造好instance好了,要么就是用volatile来修饰instance这个变量。
public class MyFactory {
private static volatile MyFactory instance;
public static MyFactory getInstance(Connection conn)
throws IOException {
if (instance == null) {
synchronized (MyFactory.class) {
if (instance == null)
instance = new MyFactory(conn);
}
}
return instance;
}
private MyFactory(Connection conn) throws IOException {
// init factory using the database connection passed in
}
}
这样就正确了,因为JAVA5为volatile带来的特性,保证unsycnrhonized volatile的读操作一定发生在写操作之后,这样读线程一定会看到MyFactory的各个field的正确的值。
还有一个解决办法是把MyFactory中的各个fields都定义成final,final的值必须在构造函数中赋值的。在JAVA5对final有了点修改,就是JVM会保证在对象引用到这块内存的时候,这些值已经提交到主存中。
我想意思大概是,一般是先分配内存,然后用指针记录这块内存,然后赋值给各个fields,但对final的field不同,需赋值之后,才把内存地址赋值给指针。
这里就可以理解为什么在ConcurrentHashMap中的HashEntry的几个fields,value是volatile的,其他的都是final的了。
四、JAVA5中volatileb的变量还有什么新的功能?
1.允许真正的get-and-set原子操作:
AtomicIntegerArray, AtomicLongArray,AtomicReferenceFieldUpdater
2.有效地访问一个volatile数组中的某个元素,而且提供在这个元素上的get-and-set院子操作
AtomicIntegerArray, AtomicLongArray and AtomicReferenceArray
这些特性是隐藏在sun.misc.Unsafe这个类中的,但以各种concurrent类的形式提供给开发人员。
分享到:
相关推荐
详细说明 并举例说明了VOlatile的作用及用法,特别是嵌入式程序员要注意的
一般对于volatile的解释是这样的:将变量定义为volatile可以防止编译器对变量进行优化,每次均从内存中访问变量,而不是寄存器。既然让编译器优化可以提高访问速度,那为什么又要不用它以及什么时候不用它?其实主要...
C语言中关键字volatile的作用,使用说明和例子
const,extern,static,volatile的使用
一般说来,volatile用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加volatile; 2、多任务环境下各任务间共享的标志应该加volatile; 3、存储器映射的硬件寄存器通常也要加volatile说明,...
const和volatile分析 这个分析得很好 面试 找工作 必备的
volatile的用法讲解,讲得很详细,希望能帮助到大家
主要讲述java线程volatile关键字
C程序中volatile关键字的使用.方法及其例程介绍。
volatile与synchronized的区别,锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)
本文给大家介绍了单片机C语言中volatile的作用。
讲述了volatile_unsigned_int地址映射的使用说明。
宏定义volatile的用法,希望和大家共同学习进步。
Java并发编程:volatile关键字解析
volatile变量的使用是区分c程序员和嵌入式系统程序员的最基本问题。不懂得volatile变量的内容将带来灾难。这个文档帮助你减少因此带来的bug。
static,const,volatile用法的解析,对三项中全局变量和局部变量的区分,volatile中介绍了其具体用法 和一些区别,bong有例子
extern_volatile等修饰符的用法
volatile 的字面含义是易变的,那么将一个变量指示为volatile 是什么意思呢?是告诉编 译器这个变量是易变的?事实上也是如此。在多任务、中断等环境下,变量可能被其他的任 务改变,而编译器无法发现,volatile ...
本文将深入分析在硬件层面上Inter处理器是如何实现Volatile的,通过深入分析能帮助我们正确的使用Volatile变量。
本篇文章主要介绍单片机中volatile定义的作用,感兴趣的朋友可以看看。