首先volatile关键字有线程安全问题。
volatile有一个专业术语:保证了可见性,不保证原子性。
首先不使用volatile关键字,看看有什么效果
public class NotUseVolatile implements Runnable { /** * 定义一个非volatile修饰的变量 */ private boolean falg = true; /** * 线程执行代码 */ public void run() { System.out.println("子线程开始执行"); while (falg) { } System.out.println("子线程执行结束"); } /** * 生成get set方法 */ public boolean isFalg() { return falg; } public void setFalg(boolean falg) { this.falg = falg; } } public class Test { public static void main(String[] args) throws InterruptedException { NotUseVolatile not = new NotUseVolatile(); Thread thread = new Thread(not, "不使用volatile关键字的线程"); thread.start(); /** * 休眠3秒: 如果不休眠,模拟不出这个效果。 */ Thread.sleep(3000); not.setFalg(false); System.out.println("flag值已修改为false"); Thread.sleep(1000); System.out.println("flag值为:" + not.isFalg()); /** * 打印结果: * * 子线程开始执行 * flag值已修改为false * flag值为:false * * ------------------------------------ * * 有没有发现,flag的值已经修改了,但是线程依然没有结束 ? * * 这是为什么呢 ? * * 这里就要说到Java的内存模型了。 * * 注意: * Java内存模型:属于线程安全的一个知识点。 * Java内存结构:属于Jvm的内存分配问题,堆、栈、方法区等。 * * 在java内存模型中,有主内存 和 线程内存两个概念: * 全局变量在主内存中,当线程操作全局变量的时候,首先是把全局变量的值复制到线程内存中去,然后线程内存修改之后,再通知主内存修改数据。 * 所以这里的flag值有几率不会被修改。 * * 但是如果我们要修改线程中的值,怎么办呢 ? * 就是再全局变量上加上volatile关键字,当加上了volatile关键字的全局变量被修改后,会去通知线程内存,最后线程内存的值也会修改为主内存所改变的值。 */ } }
使用volatile关键字:
public class UseVolatile implements Runnable { /** * 定义一个volatile修饰的变量: * * 注意:volatile关键字,只保证线程之间的可见性,但是不保证原子性(也就是说线程不安全) */ private volatile boolean falg = true; /** * 线程执行代码 */ public void run() { System.out.println("子线程开始执行"); while (falg) { } System.out.println("子线程执行结束"); } /** * 生成get set方法 */ public boolean isFalg() { return falg; } public void setFalg(boolean falg) { this.falg = falg; } } public class Test { public static void main(String[] args) throws InterruptedException { UseVolatile not = new UseVolatile(); Thread thread = new Thread(not, "使用volatile关键字的线程"); thread.start(); /** * 休眠3秒 */ Thread.sleep(3000); not.setFalg(false); System.out.println("flag值已修改为false"); Thread.sleep(1000); System.out.println("flag值为:" + not.isFalg()); /** * 打印结果: * 线程开始执行 * flag值已修改为false * 子线程执行结束 * flag值为:false * * ------------------------------------ * * 使用了volatile关键字后,就达到我们的理想效果了。 * * 注意:volatile有线程安全问题。 */ } }
所以 volatile的作用是:
每次线程读取全局变量前必须先从主内存刷新最新的值。每次线程写入后必须立即将修改的全局变量同步回主内存当中。
