首先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的作用是:
每次线程读取全局变量前必须先从主内存刷新最新的值。每次线程写入后必须立即将修改的全局变量同步回主内存当中。