java中volatile变量的使用

          首先看一段代码:

package test;

/**  
 *  VolatileTest : Volatile 关键字测试
 * @author xuejupo  [email protected] 
 * create in 2016-1-22 下午6:40:19    
 */

public class VolatileTest {
	private int number = 0;
	private int numberVolatile = 0;
	private static int numberStatic = 0;
	/**  
	 * main: 
	 * @param args 
	 * void  返回类型   
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		VolatileTest test = new VolatileTest();
		for(int i = 0; i < 10000; i++){
			//100个线程进行数据的++操作
			test.new testThread().start();
		}
		//打印最后的结果
		System.out.println("普通的number:"+test.number);
		System.out.println("static类型的number:"+numberStatic);
		System.out.println("Volatile的number:"+test.numberVolatile);
	}
	
	/**  
	* testThread:测试线程,对Volatile变量执行++操作
	* @author xuejupo  [email protected] 
	* create in 2016-1-22 下午6:40:47  
	*    
	*/
	class testThread extends Thread{
		public void run(){
			number++;
			numberStatic++;
			numberVolatile++;
		}
	}
}

    结果:

普通的number:9995
static类型的number:9995
Volatile的number:9996

       可以看到,其实将变量声明成static的,和加上volatile关键字,都不能保证线程安全的。。 

      volatile是不保证线程安全的。。  他只保证修饰变量的可见性,不保证原子性。  什么意思?我们都知道i++操作不是原子操作,他分3步操作:首先取i,然后执行i+1,然后执行i=i+1,   比如有两个线程t1和t2,t1执行i++的时候,t2恰好也在执行i++,那么他保证t1取到的i和t2取到的i跟主存中的i是一样的,但是在执行i=i+1操作的时候,t2线程可能就把t1线程覆盖了。。

      换句话说,volatile关键字保证你的所有线程取到的变量都是最新的,但是不保证正确性。

      什么情况下使用volatile关键字?    

       首先能想到的自然是状态标志位。

       打个比方,多个线程执行同一任务,可以设置一个标志位boolean  isDown表示是否有线程完成任务。isDown就适合用volatile关键字。因为如果不用volatile,那么单个线程修改变量之后对主存的更新是有延迟的(上面的代码结果中volatile变量比普通的大1,也能说明这一点)。当然,这种延迟大部分情况下是无影响的,但是最好加上volatile关键字。

       然后,能想到的适合用volatile关键字的地方就是在上面的代码里,如果对变量的改变只是一个线程,而其他线程都是对变量的读取,并且需要变量的最新值,那么这种情况下个人觉得最适合用volatile关键字修饰。比如说天气预报系统,对天气类的更新可能只有一个线程,而对天气类的读取可能很多个线程并发执行,这种情况下太适合用volatile了。

       简而言之,就是volatile保证了数据的一致性,即某线程对变量的更新能马上同步到主存,在原子操作中,他是线程安全的,但是他不保证数据操作的原子性,在非原子性操作中他不是线程安全的(比如i++)

        

猜你喜欢

转载自709002341.iteye.com/blog/2273421