volatile 的实现机制和使用场景

一 实现机制

volatile 关键字可以保证可见性和顺序性,那么它是如何做到的呢?

volatile 底层是通过内存屏障机制实现的,该内存屏障会为指令的执行提供如下几个保障。

  • 确保指令重排时不会将其后面的代码排到内存屏障之前。
  • 确保指令重排时不会将其前面的代码排到内存屏障之后。
  • 确保在执行到内存屏障修饰的指令时前面的代码全部执行完成。
  • 强制将线程工作内存中的值的修改刷新到主内存中。
  • 如果是写操作,则会导致其他线程工作内存(CPU Cache)中的缓存数据失效。

二 volatile 的使用场景

虽然 volatile 有部分 synchronized 关键字语义,但是 volatile 不可能完全替代 synchronized 关键字,因为 volatile 关键字不具备原子性操作语义,我们在使用 volatile 关键字的时候也是充分利用它的可见性以及有序性(防止重排序)特点。

1 开关控制利用可见性的特点

package concurrent;

public class ThreadCloseable extends Thread {
    // volatile 关键字保证了 started 线程的可见性
    private volatile boolean started = true;

    @Override
    public void run() {
        while (started) {
            // do work
        }
    }

    public void shutdown() {
        this.started = false;
    }
}

当外部线程执行 ThreadCloseable 的 shutdown 方法时,ThreadCloseable 会立刻看到 started 发生了变化,原因是 ThreadCloseable 工作内存中的 started 失效了,不得不到主内存中重新获取。

如果 started 没有被 volatile 关键字修饰,那么很有可能外部线程在其工作内存中修改了 started 之后不及时刷新到主内存,或者 ThreadCloseable 一直到自己的工作内存中读取 started 变量,因为无法感知 started 的变化,导致线程无法关闭。

2 状态标记利用顺序性特点

private volatile boolean initialized = false;
private Context context;
public Context load(){
    if(!initialized){
        context = loadContext();
        initialized = true; // 阻止重排序
    }
    return context;
}

initialized 加了 volatile 会防止指令重排序

3 单例设计模式的 double-check 也是利用了顺序性特点。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值