架构师之路第一天

Volatile关键字

用处:Volatile修饰的变量能够在多线程之间可见。也就是可用此关键字实现变量在多线程之间的数据一致性。

在没有Volatile之前,是通过在变量或者方法上面进行加锁实现的。那样的话,效率不高。

案例:


public class VolatileTest extends Thread{
	private boolean flag = true;
	public boolean isFlag() {
		return flag;
	}
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	@Override
	public void run() {
		while(flag)
		{	
		}
		System.out.println("线程结束");
	}
	public static void main(String[] args) throws Exception {
		VolatileTest test = new VolatileTest();
		test.start();
		Thread.sleep(3000);
		test.setFlag(false);
		System.out.println("已经将falg设置为了false");
		System.out.println(test.isFlag());
	}
}

上述的结果为:

已经将falg设置为了false
false

并没有出现线程结束的打印,也就是说线程并没有正常结束。

原因分析:在主线程中开启了一个test的线程,然后主线程休眠了3秒。这个时候再去到主线程的test引用赋值了flag为false,这个赋值的flag并没有影响到test线程中的flag变量的(这个机制是JDK的一个优化策略:开启一个新的线程会开辟一个内存用来保存线程中用到的变量,这个变量是该线程特有的。在主线程中用到的变量还是主线程的变量,不会影响到其他线程的变量)。

解决办法:将flag这个变量使用Volatile关键字修饰,使得该变量可以在多线程之间显示,从而实现上述的正确结果。因为volitile修饰的变量后,该变量改变会强制到主内存去读取,并将改变后值加载到开辟的内存中。如下:

public class VolatileTest extends Thread{
	private volatile boolean flag = true;
	public boolean isFlag() {
		return flag;
	}
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	@Override
	public void run() {
		while(flag)
		{	
		}
		System.out.println("线程结束");
	}
	public static void main(String[] args) throws Exception {
		VolatileTest test = new VolatileTest();
		test.start();
		Thread.sleep(3000);
		test.setFlag(false);
		System.out.println("已经将falg设置为了false");
		System.out.println(test.isFlag());
	}
}

允许的结果为:

已经将falg设置为了false
线程结束
false

注意:Volatile是没有原子性的,在多个线程访问的时候还是会出现数据不同步的现象。Volatile只是保证其修饰的变量在多线程之间显示,也就是能够在多个线程之间访问得到,并且对其能够进行操作受到影响的,并不能保证其数据的一致性的。如果需要保证其原子性,那么这个时候可以使用关键词AtomicInteger

 

猜你喜欢

转载自blog.csdn.net/javashareauthor/article/details/83149243
今日推荐