Volatile 是 Java 虚拟机提供的轻量级
的同步机制(三大特性)
考虑一下这种场景:
有一个对象的字段number
初始化值=0,另外这个对象有一个公共方法setNumberTo100()
可以设置 number = 100,当主线程通过子线程来调用setNumberTo100()
后,主线程是否知道 number 值变了呢?
答案:如果没有使用 volatile 来定义 number 变量,则主线程不知道子线程更新了 number 的值。
(1)定义如上述所说的对象:ShareData
class ShareData {
int number = 0;
public void setNumberTo100() {
this.number = 100;
}
}
复制代码
(2)主线程中初始化一个子线程,名字叫做子线程
子线程先休眠 3s,然后设置 number=100。主线程不断检测的 number 值是否等于 0,如果不等于 0,则退出主线程。
public class volatileVisibility {
public static void main(String[] args) {
// 资源类
ShareData shareData = new ShareData();
// 子线程 实现了Runnable接口的,lambda表达式
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t come in");
// 线程睡眠3秒,假设在进行运算
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 修改number的值
myData.setNumberTo100();
// 输出修改后的值
System.out.println(Thread.currentThread().getName() + "\t update number value:" + myData.number);
}, "子线程").start();
while(myData.number == 0) {
// main线程就一直在这里等待循环,直到number的值不等于零
}
// 按道理这个值是不可能打印出来的,因为主线程运行的时候,number的值为0,所以一直在循环
// 如果能输出这句话,说明子线程在睡眠3秒后,更新的number的值,重新写入到主内存,并被main线程感知到了
System.out.println(Thread.currentThread().getName() + "\t 主线程感知到了 number 不等于 0");
/**
* 最后输出结果:
* 子线程 come in
* 子线程 update number value:100
* 最后线程没有停止,并行没有输出"主线程知道了 number 不等于0"这句话,说明没有用volatile修饰的变量,变量的更新是不可见的
*/
}
}
复制代码
(3)我们用 volatile 修饰变量 number
class ShareData {
//volatile 修饰的关键字,是为了增加多个线程之间的可见性,只要有一个线程修改了内存中的值,其它线程也能马上感知
volatile int number = 0;
public void setNumberTo100() {
this.number = 100;
}
}
复制代码
输出结果:
子线程 come in
子线程 update number value:100
main 主线程知道了 number 不等于 0
Process finished with exit code 0
复制代码
**小结:说明用 volatile 修饰的变量,当某线程更新变量后,其他线程也能感知到。
评论