Java中volatile关键字的效果
来源:互联网 发布:最好家庭网络理财投资 编辑:程序博客网 时间:2024/05/29 19:07
使用volatile和不使用volatile的区别在于JVM内存主存和线程工作内存的同步之上。volatile保证变量在线程工作内存和主存之间一致。以下是示例程序,成员变量boolValue用volatile修饰会导致程序很快退出:
Java代码
package linyumin.test.thread;
/**
*
* @author llade
*
*/
public class VolatileObjectTest {
/**
* 成员变量boolValue使用volatile和不使用volatile会有明显区别的。
* 本程序需要多试几次,就能知道两者之间的区别的。
* @param args
*/
public static void main(String[] args) {
final VolatileObjectTest volObj= new VolatileObjectTest();
Thread t1=new Thread(){
public void run(){
System.out.println("t1 start" );
for (;;){
volObj.waitToExit();
}
}
};
t1.start();
Thread t2=new Thread(){
public void run(){
System.out.println("t2 start" );
for (;;){
volObj.swap();
}
}
};
t2.start();
}
boolean boolValue; //加上volatile 修饰的是时候,程序会很快退出,因为volatile 保证各个线程工作内存的变量值和主存一致。所以boolValue == !boolValue就成为了可能。
public void waitToExit() {
if (boolValue == !boolValue)System.exit( 0 ); //非原子操作,理论上应该很快会被打断。实际不是,因为此时的boolValue在线程自己内部的工作内存的拷贝,因为它不会强制和主存区域同步,线程2修改了boolValue很少有机会传递到线程一的工作内存中。所以照成了假的“原子现象”。
}
public void swap() { //不断反复修改boolValue,以期打断线程t1.
boolValue = !boolValue;
}
}
首先每个线程都有自己一个工作内存区,多个线程共享一个主内存区。线程中的本地变量存在自己的内存区中,如for(int i=0;i <100;i++){this.i=i;},其中i就存在线程工作内存中,即每个线程都有一个,不用也不能加volatile关键字,this.i就是共享变量。而共享的变量就存在主内存区里,但Java线程为了提高效率,会把共享变量拷贝到自己的工作区中,这就产生了变量一致性的问题。
java提供的一种方法是互斥访问,互斥访问会在加锁和解锁中维持变量的一致性,另一种就是volatile关键字。
java language specification中的一个例子,有类如下:
class Test {
static int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println( "i= " + i + " j= " + j);
}
}
有两个线程,一个不停调用 one(),一个不停调用 two(),则有可能出现这种情况,打印出来的j比i还大。因为这时线程对共享变量的更新是无序的。
1.使用同步方法:
class Test {
static int i = 0, j = 0;
static synchronized void one() { i++; j++; }
static synchronized void two() {
System.out.println( "i= " + i + " j= " + j);
}
}
这就不用我介绍了,i和j始终一样大。
2.使用volatile
class Test {
static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println( "i= " + i + " j= " + j);
}
}
这样能允许one()和two()并发执行,同时使one()如字面一样执行。这一般能使打印出来的j不会大于i,在更新j之前会先更新i。但有可能打印出来的j比i大很多,因为one()可能在two获取i和j之间执行了很多次。
说明一下:
java language specification中的例子不好,有点晦涩,但我认为volatile的作用就是保证任何时候主内存的i都大于等于j。two()中出现j比i大很多,只是因为它访问的是不同时刻的主内存。
还有一点,就是volatile能防止编译器对变量进行优化,每次共享变量都到主内存。如果线程不到主内存中读,变量的值就会不正确。
强制线程到主存中读,应该也包含上面wulemale所说的,变量被程序外部改变的情况。
- Java中volatile关键字的效果
- Java中volatile关键字的效果
- Java中volatile关键字的效果
- Java:java中关键字volatile的作用
- java中volatile关键字
- Java中 volatile 关键字
- java中volatile关键字
- java中volatile关键字
- Java中Volatile关键字
- java中volatile关键字
- java中volatile 关键字
- java 中volatile关键字
- Java中volatile关键字
- java中volatile关键字
- java中关键字volatile
- java中volatile关键字
- java中volatile关键字
- java中volatile关键字
- 使用SQL语句生成站点导航树形结构的实例
- VC中判断文件夹是否存在的方法(C/C++)
- 光脚丫学LINQ(031):开篇及一对多映射关系的再学习
- JDBC批量执行sql(转)
- Firebird 数据库使用经验总结
- Java中volatile关键字的效果
- RUP开发实践
- Subversion 错误信息一览表
- XP 极限编程
- 数据表设计实例文档版本管理系统表设计
- 9.4 vector容器的自增长
- Firebird笔记
- 关于:VC控制台结束时暂停
- C#方向高级开发人员面试时应该事先考虑的问题