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类的形式提供给开发人员。
分享到:
相关推荐
### STM32中Volatile变量的正确使用 #### 概述 在嵌入式系统编程中,`volatile`关键字的正确使用对于确保程序的稳定性和可靠性至关重要。它主要用于标记那些可能在程序运行过程中被外部因素(如硬件中断、多线程...
《深入理解Volatile》 Volatile是C/C++编程语言中的一个关键字,它与const一起被称为"cv特性",用于指示变量的值可能被系统或其他线程/进程改变,从而强制编译器每次从内存中读取该变量的最新值。在多线程或嵌入式...
"volatile的用法讲解" volatile是一种特殊的变量修饰符,它告诉编译器,这个变量的值可能会被意外地改变,因此编译器不能对其进行优化,以确保每次读取该变量时都能获取最新的值。下面是volatile变量的使用场景: ...
### const、extern、static、volatile 的使用详解 #### 一、const 的使用 **1. 为什么使用 const** `const` 关键字在 C 和 C++ 编程语言中非常常见,它用来声明一个常量或者指定某个变量的某个方面为不可变。使用...
volatile 关键字在 C 语言中的使用方法 在 C 语言中,volatile 关键字是用来指定变量的存储类别的,它告诉编译器这个变量的值可能会在编译器不知道的情况下被修改,因此需要重新加载这个变量的值。volatile 关键字...
在C++编程语言中,`const`和`volatile`是两个非常重要的关键字,它们用于修饰变量,赋予变量特殊的属性。这两个关键字在理解程序的行为、内存模型以及多线程编程中起到至关重要的作用。在此,我们将深入探讨`const`...
Java 线程 volatile 关键字详解 Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。volatile 变量的同步性较差,但它有时更简单并且开销更低。volatile 变量可以被看作是一种 “程度较轻的 ...
【volatile源码分析1】 Java中的volatile关键字是一个关键的同步机制,它在多线程编程中扮演着重要的角色。在面试和技术讨论中,volatile经常成为焦点,但其工作原理却常常引发争议。本文将从JVM、C++以及汇编语言...
### 单片机C语言中volatile的作用 在探讨单片机C语言中`volatile`关键字的作用之前,我们首先需要理解`volatile`的基本概念及其应用场景。`volatile`是一个用于声明变量的关键字,在C语言中,使用`volatile`修饰的...
单片机中volatile定义的作用 单片机中volatile定义的作用是指在单片机编程中,使用volatile关键字来定义变量,使编译器认为该变量可能会被意外地改变,从而避免编译器对该变量的优化。这样,编译器将每次都重新读取...
本文实例讲述了C#中volatile与lock用法,分享给大家供大家参考。具体分析如下: 一、C#中volatile volatile是C#中用于控制同步的关键字,其意义是针对程序中一些敏感数据,不允许多线程同时访问,保证数据在任何访问...
### 宏定义与`volatile`关键字的理解 #### 1. 宏定义的解析 在给定的代码片段中,我们看到一系列宏定义被用来访问硬件寄存器。这些宏定义通常用于嵌入式系统编程中,以便以一种类型安全且易于理解的方式访问硬件...
### C中`volatile`与`const`解析 #### 概述 在C语言中,`volatile`和`const`是两个非常重要的关键字,它们在不同的场景下有着独特的用途。掌握这两个关键字不仅能够帮助开发者写出更加高效和可靠的代码,还能够在...
标题“volatile_unsigned_int”以及描述“讲述了volatile_unsigned_int地址映射的使用说明”指向了C语言中特殊的关键词“volatile”以及其与“unsigned int”类型的结合使用。该知识点主要涉及硬件编程,特别是在...
《从汇编角度理解volatile》 volatile关键字在编程中扮演着重要的角色,它主要用于多线程编程和与硬件交互的场景。通常的理解是,volatile告诉编译器不要对某个变量进行优化,每次读取该变量时都直接从内存中获取,...
本文将围绕宏定义`#define XBYTE ((unsigned char volatile xdata *) 0)`展开,深入探讨其含义、作用以及应用场景。 #### 宏定义详解 宏定义`#define XBYTE ((unsigned char volatile xdata *) 0)`主要包含以下几...
### Java并发编程:volatile关键字解析 #### 一、内存模型的相关概念 在深入了解`volatile`关键字之前,我们首先需要理解计算机内存模型的一些基本概念。在现代计算机系统中,CPU为了提高执行效率,会将频繁访问的...
在C语言中,关键字volatile是一个非常重要的修饰符,它在程序设计中起着不可替代的作用。volatile的主要目的是告诉编译器,它所修饰的变量是易变的,可能会在程序的控制之外被改变。因此,编译器在优化代码时,不能...
"extern_volatile等修饰符的用法" 在C++语言中,extern、volatile、const、static等修饰符都是非常重要的,它们可以影响变量的存储方式、生命周期和访问权限等。本文将详细介绍这些修饰符的用法和特点。 一、const...