多线程(二)volatile关键字详解

volatile关键字,几乎是面试必问的话题,但是我浏览了所有的网页并没有发现正确清晰的例子。都是一些概念上的解答,本文通过一个测试过的Java实例,来讲解volatile关键字的用法和场景。

1.概念

我也先简单讲一下概念,让初学者有点了解。并发,有可见性和原子性两种。volatile只保证了可见性遵循happen-before原则,不保证原子性。所以这个关键字不能作为计数器使用(计数器取值,+1,赋值,3步操作)。可见性主要是保证每次都去内存中取变量值,不在高速缓冲寄存器中进行取值,保证不会发生值改变,你使用的时候有没有改变。

2.网上说法

先说几个网上的实例,这是网上最常见实例,也是权威书籍《并发编程实践》的例子,但是我测试多次并没有发生问题。

网上对此有两种解释,一种是指令重排序无法确定是否是read先赋值,还是num先赋值。另一种,是jvm在server模式下。线程会复制原对象信息放到栈中,所以不会读取到read赋值为true,会发生死循环。以上两种都没有发生。

package com.ldh.valid;

/**
 * 并发编程中,因为指令重排序会出现 0,死循环。
 * 单机i5,4核,无异常
 * @author liudonghe
 *
 */
public class Vol2 extends Thread{
	//测试不加volatile关键字
	private static volatile boolean read;
	private static int num;
	@Override
	public void run() {
		while(!read){
			yield();
		}
		System.out.println(num);
	}
	
	
	public static void main(String[] args) {
		new Vol2().start();
		read = true;
		num = 42;
	}
}




可能是本机没有高并发环境无法测试。同时我又结合阿里的开发规范,其中指出volatile 使用在一写多读场景下。我就写下了如下demo。
3.我的demo


/**
 * 并发编程中,如果不加入volatile关键字,发生死循环,加入无问题。
 * 单机i5,4核,死循环。
 * @author liudonghe
 *
 */
public class Vol extends Thread{
	private static volatile boolean read;
	private static int num;
	@Override
	public void run() {
		while(!read){
		}
		System.out.println(num);
	}
	
	
	public static void main(String[] args) {
		for(int i=0;i<80;i++){
			new Vol().start();
		}
		read = true;
		num = 42;
	}
}


不加volatile关键字测试图如下:


没有结束发生了死循环。这里需要注意我的while循环中没有代码。因为有了代码。执行的速度不足以发生并发,毕竟我的测试线程只有80个。
在看一下加上volatile关键字的结果。


测试结果很明显,没死循环。




总结。在一些多读场景下,标志变量,需要加上volatile关键字,防止死循环的发生。

你可能感兴趣的:(java-多线程)