关键字volatile的详细解析

 volatile 关键字的作用是什么?

相比于 synchronized 关键字(重量级锁)对性能影响较大,Java提供了一种较为轻量级的可见性和有序性问题的解决方案,那就是使用 volatile 关键字。由于使用 volatile 不会引起上下文的切换和调度,所以 volatile 对性能的影响较小,开销较低。

从并发三要素的角度看,volatile 可以保证其修饰的变量的可见性有序性,无法保证原子性(不能保证完全的原子性,只能保证单次读/写操作具有原子性,即无法保证复合操作的原子性)。

下面将从并发三要素的角度介绍 volatile 如何做到可见和有序的。


1. volatile 如何实现可见性?

什么是可见性?

可见性指当多个线程同时访问共享变量时,一个线程对共享变量的修改,其他线程可以立即看到(即任意线程对共享变量操作时,变量一旦改变所有线程立即可以看到)。

1.1 可见性例子

/**
 * volatile 可见性例子
 * @author 单程车票
 */
public class VisibilityDemo {

    // 构造共享变量
    public static boolean flag = true;
//    public static volatile boolean flag = true;   // 如果使用volatile修饰则可以终止循环

    public static void main(String[] args) {
        // 线程1更改flag
        new Thread(() -> {
            // 睡眠3秒确保线程2启动
            try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}
            // 修改共享变量
            flag = false;
            System.out.println("修改成功,当前flag为true");
        }, "one").start();

        // 线程2获取更新后的flag终止循环
        new Thread(() -> {
            while (flag) {

            }
            System.out.println("获取到修改后的flag,终止循环");
        }, "two").start();
    }
}
复制代码
  • 不使用 volatile 修饰 flag 变量时,运行程序会进入死循环,也就是说线程1对 flag 的修改并没有被线程2读到,也就是说这里的flag并不具备可见性。

  • 使用 volatile 修饰 flag 变量时,运行程序会终止循环,打印提示语句,说明线程2读到了线程1修改后的数据,也就是说被 volatile 修饰的变量具备可见性。


1.2 volatile 如何保证可见性?

volatile 修饰的共享变量 flag 被一个线程修改后,JMM(Java内存模型)会把该线程的CPU内存中的共享变量 flag 立即强制刷新回主存中,并且让其他线程的CPU内存中的共享变量 flag 缓存失效,这样当其他线程需要访问该共享变量 flag 时,就会从主存获取最新的数据。

所以通过

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值