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:100main 主线程知道了 number 不等于 0
Process finished with exit code 0
复制代码
**小结:说明用 volatile 修饰的变量,当某线程更新变量后,其他线程也能感知到。
评论