JAVA volatile 关键字详解

来源:互联网 发布:淘宝家具店排名 编辑:程序博客网 时间:2024/06/11 21:09

volatile可以简单理解为确保多线程安全的手段,但现实情况下,volatile并不能代替synchronized。

volatile有两个作用:

作用1:在多线程工作模式下,确保一个线程修改了volatile修饰的变量,对其他线程立刻可见。但该机智并不能保证被volatile修饰的变量的正确性,看下面的例子↓

public static volatile int race = 0;

public static void main(String[] args) {
Thread[] threads = new Thread[10];
//启动10个线程做累加工作
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
for (int j = 0; j < 10000; j++) {
race++;
}
}
});
threads[i].start();
}
//等待所用线程执行完成
while(Thread.activeCount()>1)
Thread.yield();
//此处的值,并非我们认为的100000,会是一个小于100000的值
System.out.println(race);
}

为什么不是100000呢?这与jvm的执行字节码的方式有关,race++操作,在编译为字节码后,会产生4个操作,

getstatic

iconst_1

iadd

putstatic

第一个操作是将race变量push到操作栈顶,这个时候因为变量定义为volatile,所以值是正确的,iconst_1 将1常量放入操作栈顶,但下一个指令,iadd,putstatic时,其他线程很可能已经改变了race的值,操作栈又是线程私有的内存空间,所以,结果出现了偏差。


作用2:禁止指令的重新排序

这个是对于虚拟机层面的表述,普通变量仅仅会在方法执行过程中,所有依赖赋值结果的地方,都已经进行正确的赋值操作,但并不能保证赋值的顺序跟代码书写的一样,volatile修饰的变量,确实禁止对执行指令的重新排序优化。该作用在现实开发中应用不大,

int a = 1;

int b = 3;

上面的两行代码,并不能保证a一定比b先赋值。


我的总结是:volatile定义的变量不应该进行频繁的赋值操作,或者说,仅仅有一个线程负责写入,其他线程负责读取,做到一个广播的效果,如下面的伪代码:

public static volatile boolean init = false;

Thead1.setInit(true);


Thead2.run()

{

while(true)

if(init)

break;

}



0 0
原创粉丝点击