volatile关键字

 首先创建一个MyThread类,继承Thread,有一个成员变量flag,重写run方法:

package com.lit.thread003;

public class MyThread extends Thread{
	private  boolean flag = true ;
	
	public boolean isFlag() {
		return flag;
	}
	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	@Override
	public void run() {
		System.out.println("---进入run方法---");
		while(flag){
			//System.out.println("我在while循环中");
		}
		System.out.println("---结束run方法---");
	}
	
}

  

  然后,创建Run类,如下:

package com.lit.thread003;

public class Run {
	public static void main(String[] args) {
		
		try {
			final MyThread thread = new MyThread() ;
			thread.start();
			Thread.sleep(1000);
			
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					thread.setFlag(false);
				}
			}).start();
			System.out.println("set false");
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

  运行结果如下:

---进入run方法---
set false

  可以看到,程序的运行结果出现了死循环,另一个线程修改了flag的值为false之后,并没有跳出循环,这是因为在执行代码thread.start()启动这个线程时,变量private boolean flag = true存在于公共堆栈以及线程的私有堆栈中。为了提高线程的运行效率,线程一直从私有堆栈中取得flag的值是true,而代码 thread.setFlag(false); 虽然被执行,但是更新的确是公共堆栈中的flag变量值false,所以程序一直是死循环的状态。

  解决公共堆栈和私有堆栈值不同可以使用关键字volatile,它的主要作用是当前线程访问flag这个变量的时候,强制性的从公共堆栈读取。

  将MyThread.java的代码更改如下:

public class MyThread extends Thread{
	private volatile  boolean flag = true ;
	
	public boolean isFlag() {
		return flag;
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	@Override
	public void run() {
		System.out.println("---进入run方法---");
		while(flag){
			//System.out.println("我在while循环中");
		}
		System.out.println("---结束run方法---");
	}
	
}

  运行Run.java  :

---进入run方法---
set false
---结束run方法---

  问题解决。

  但是仍然需要注意的是volatile关键字虽然增加了实例变量在多个线程之间的可见性,但是它的缺点在于不支持原子性。

 

posted @ 2017-02-12 12:33  dquery  阅读(265)  评论(0编辑  收藏  举报