Volatile作用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dongyuxu342719/article/details/88887522

在多线程环境下,对于主内存中的共享变量,每个线程都有自己的一份拷贝值,便于自己线程内的操作,这也会导致一个问题,当有一个线程修改主内存中的变量值时,其他线程内拷贝的变量值还是旧值,没有获取最新的值。因此我们就可以使用volatile关键字修饰变量,它可以保证内存可见性和避免指令重排序。当有线程修改主内存中的变量值时,会导致其他线程中拷贝的变量值失效,当线程内读取自己线程内存中的变量值时会发现变量值已失效,就会从主内存重新读取变量值到自己线程内存中。以此来达到及时获取最新的变量值。但是volatile没有synchronized的同步原语,无法保证原子性。即在变量操作环境下仍然是不安全的。比如,volatile修饰的变量,两个线程a、b已经读取了主内存中的变量值并进行++操作,其中a线程先进行++操作,并更新主内存中的变量值,同时使b线程内的变量缓存值失效,但是如果b线程已经在a线程更新变量值之前就读取过了变量值,b就不会再重新读取主内存的值,即使这时缓存的值已经失效,b线程就会在原来的值基础上进行++操作,导致操作错误。

下面看一下在没有volatile关键字修饰时,修改变量的值不能时循环停止的情况。

/**
 * Volatile保证变量内存可见性
 * @author SN
 *
 */
public class VolatileRead extends Thread{
	private /*volatile*/ boolean flag=true;
	
	public void setValue(boolean flag){
		this.flag=flag;
		System.out.println("设置flag:"+flag);
	}
	
	@Override
	public void run(){
		//run方法内是另启动的线程,其使用的flag值是线程内拷贝的主内存的值
		while (flag) {
			//System.out.println("#########");
		}
		System.out.println("循环结束,flag:"+flag);
	}
	
	public static void main(String[] args) throws InterruptedException {
		VolatileRead vr=new VolatileRead();
		vr.start();
		Thread.currentThread().sleep(3000);
		vr.setValue(false);
		System.out.println("flag:"+vr.flag);
	}
}

执行程序,可以看到程序没有停止,仍然在循环,这是因为虽然在main方法中修改了flag的值,但是由于while循环是在另外启动的线程中运行的,这个线程中读取的flag值是线程内缓存的主内存中的flag值,仍然是true,所以循环没有结束。如果将flagvolatile修饰就可以了。

另外在while循环中加上一句System.out的打印语句也可以使线程停止,因为System.outjdk线程调用的,怀疑是自动刷新了线程内的flag值。

猜你喜欢

转载自blog.csdn.net/dongyuxu342719/article/details/88887522
今日推荐