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关键字虽然增加了实例变量在多个线程之间的可见性,但是它的缺点在于不支持原子性。