volatile 是并发编程中的重要关键字,它的名气甚至是可以与 synchronized、ReentrantLock 等齐名,也是属于并发编程五杰之一。

需要注意的是 volatile 并不能保证原子性,因此使用 volatile 并没有办法保证线程安全

并发编程五杰:

PS:“并发编程五杰”是我个人起的名字,大家也不用太当真。

1.什么是 volatile?

volatile 是 Java 中的一个关键字,用于修饰变量,它的主要作用是保证变量的可见性和禁止指令重排序

  • 可见性:是指当一个线程修改了一个被 volatile 修饰的变量时,其他线程能够立即看到这个修改。
  • 禁止指令重排序:则是确保对 volatile 变量的读写操作不会被编译器或处理器随意重新排序,从而保证了程序执行的顺序符合我们的预期。

2.volatile 工作原理

为了实现可见性,Java 内存模型(JMM)会在对 volatile 变量进行写操作时,强制将工作内存中的值刷新到主内存,并在读取时强制从主内存中重新获取最新的值。

而禁止指令重排序是通过在编译器和处理器层面添加特定的内存屏障指令来实现的。

具体来说。

2.1 可见性实现原理

可见性:在计算机编程特别是多线程编程中,“可见性”指的是一个线程对共享变量的修改,对于其他线程是否能够及时地、准确地“可见”,即其他线程是否能够及时感知到这个修改并获取到最新的值。

例如,在一个多线程环境中,如果线程 A 修改了一个共享变量的值,而线程 B 无法立即看到这个修改,那么就存在可见性问题。

多线程操作共享变量流程如下:



volatile 是通过内存屏障(Memory Barrier) 来确保可见性。

  • 写屏障(Store Barrier):在 volatile 变量的写操作之后插入写屏障,确保所有之前的写操作都同步到主内存中,从而使得其他线程在读取该变量时能够获取到最新的值。
  • 读屏障(Load Barrier):在 volatile 变量的读操作之前插入读屏障,确保所有之前的写操作都已完成,从而读取到的是最新的值。

通过这种方式,volatile 变量在多线程环境下的读写操作能够保持较高的可见性,但需要注意的是,volatile 并不保证操作的原子性。

具体来说,volatile 内存可见性主要通过 lock 前缀指令实现的,它会锁定当前内存区域的缓存(缓存行),并且立即将当前缓存行数据写入主内存(耗时非常短),回写主内存的时候会通知其他线程缓存了该变量的地址失效,从而导致其他线程需要重新去主内存中重新读取数据到其工作线程中。

2.2 有序性实现原理

volatile 的有序性是通过插入内存屏障,在内存屏障前后禁止重排序优化,以此实现有序性的。

2.3 正确理解“内存屏障”?

volatile 保证可见性的“内存屏障”和保证有序性的“内存屏障”有什么区别呢?

在说它们的区别之前,我们现需要对“内存屏障”有一个大致的理解。

内存屏障,简单来说,就像是在内存操作中的一道“关卡”或者“栅栏”。

想象一下,计算机在执行程序的时候,为了提高效率,可能会对指令的执行顺序进行一些调整。但是在多线程或者多核心的环境下,这种随意的调整可能会导致一些问题。

内存屏障的作用就是阻止这种随意的调整,确保特定的内存操作按照我们期望的顺序执行。

所以“内存屏障”本身只是一种“技术”,而这种“技术”可以实现很多“业务功能”。

这就像 Spring 中的 AOP 一样,AOP 是一种“技术”,而这种技术可以实现很多业务功能。例如,针对日志处理可以使用 AOP、针对用户鉴权可以使用 AOP 等,而内存屏障也是一样,我们可以使用内存屏障实现可见性的“业务功能”,也可以实现有序性的“业务功能”等。

3.volatile 适用场景

volatile 常见场景有以下两种:

  1. 状态标记
  2. 单例模式中的双重检查锁

具体来说。

3.1 状态标记

例如,在多线程环境中用于表示某个任务是否完成的标志变量,具体代码如下:

volatile boolean isTaskFinished = false;

3.2 单例模式中的双重检查锁

class Singleton {
private volatile static Singleton instance; public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

4.volatile 局限性

volatile 并不能保证原子性,也就是并不能保证线程安全

例如,对于 i++ 这样的操作,它不是一个原子操作,单纯使用 volatile 修饰 i 并不能保证线程安全。

课后思考

为什么双重效验锁一定要加 volatile?不是已经加锁了吗?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

面试官:说说volatile应用和实现原理?的更多相关文章

  1. 面试官:volatile关键字用过吧?说一下作用和实现吧

    volatile    可见性的本质类似于CPU的缓存一致性问题,线程内部的副本类似于告诉缓存区 面试官:volatile关键字用过吧?说一下作用和实现吧 https://blog.csdn.net/ ...

  2. 面试官再问你 HashMap 底层原理,就把这篇文章甩给他看

    前言 HashMap 源码和底层原理在现在面试中是必问的.因此,我们非常有必要搞清楚它的底层实现和思想,才能在面试中对答如流,跟面试官大战三百回合.文章较长,介绍了很多原理性的问题,希望对你有所帮助~ ...

  3. 面试官:SpringBoot jar 可执行原理,知道吗?

    文章篇幅较长,但是包含了SpringBoot 可执行jar包从头到尾的原理,请读者耐心观看.同时文章是基于 SpringBoot-2.1.3进行分析.涉及的知识点主要包括Maven的生命周期以及自定义 ...

  4. 面试官最爱的volatile关键字

    在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性 ...

  5. Java面试官最爱问的volatile关键字

    在Java的面试当中,面试官最爱问的就是volatile关键字相关的问题.经过多次面试之后,你是否思考过,为什么他们那么爱问volatile关键字相关的问题?而对于你,如果作为面试官,是否也会考虑采用 ...

  6. 面试官:说一下Synchronized底层实现,锁升级的具体过程?

    面试官:说一下Synchronized底层实现,锁升级的具体过程? 这是我去年7,8月份面试的时候被问的一个面试题,说实话被问到这个问题还是很意外的,感觉这个东西没啥用啊,直到后面被问了一波new O ...

  7. 面试中的volatile关键字

    在Java的面试当中,面试官最爱问的就是volatile关键字相关的内容.经过多次面试之后,你是否思考过,为什么他们那么爱问volatile关键字相关的问题?而对于你,如果作为面试官,是否也会考虑采用 ...

  8. 反制面试官 | 14张原理图 | 再也不怕被问 volatile!

    反制面试官 | 14张原理图 | 再也不怕被问 volatile! 悟空 爱学习的程序猿,自主开发了Java学习平台.PMP刷题小程序.目前主修Java.多线程.SpringBoot.SpringCl ...

  9. 漂亮回答面试官struts2的原理

    众所周知,Struts2是个非常优秀的开源框架,我们能用Struts2框架进行开发,同时能快速搭建好一个Struts2框架,但我们是否能把Struts2框架的工作原理用语言表达清楚,你表达的原理不需要 ...

  10. JVM工作原理和特点(一些二逼的逼神面试官会问的问题)

    作为一种阅读的方式了解下jvm的工作原理 ps:(一些二逼的逼神面试官会问的问题) JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完毕,通过以下4步来完毕JVM环境. ...

随机推荐

  1. Woothosting 6$/年 vps测评

    当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解 Woothosting 6$/年 vps测评** 日期:2018-7- ...

  2. 深入了解 C# Span:高性能内存操作的利器

    深入了解 C# Span:高性能内存操作的利器 在 C# 7.2 中引入的 Span<T> 类型为我们提供了一种高效且安全地对内存进行操作的方式.Span<T> 是一个轻量级的 ...

  3. .NET 高效灵活的API速率限制解决方案

    前言 FireflySoft.RateLimit是基于.NET Core和.NET Standard构建,支持多种速率限制算法和策略,包括固定窗口.滑动窗口.漏桶.令牌桶等.通过简单的配置和集成,开发 ...

  4. Gerrit 大量代码提交流程优化

    # Gerrit 大量代码提交流程优化 背景 本文适用于 提交大量初始代码 的场景(仓库版本的早期). 有时候提交大量代码到Gerrit的时候会提示: $ git push Counting obje ...

  5. 从零开始带你上手体验Sermant自定义插件开发

    本文分享自华为云社区<Sermant自定义插件开发上手体验>,作者:华为云开源. 一.研究缘由 由于目前我们所处的行业是汽车行业,项目上进行云服务的迁移时使用到了Sermant中的相关插件 ...

  6. .NET Framework 4 请求https接口

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net ...

  7. Mac mysql5.7.x my.cnf默认配置

    配置如下 [client] port = 3306 default-character-set=utf8 [mysqld] character_set_server=utf8 datadir=/usr ...

  8. PowerBuilder现代编程方法X11:PB程序完全跨平台方案

    PB可能要支持Windows.macOS.Linux.iOS.Android与鸿蒙操作系统和X86.ARM.RISC-V与国产龙芯CPU的原生应用了! PowerBuilder现代编程方法X11:PB ...

  9. [oeasy]python0119_语言的演化_拉丁字符_罗马帝国_罗马体

    罗马拉丁字符 回忆上次内容 起源于埃及的 圣书体 象形文字 在与 两河流域的 苏美尔楔形文字 结合后 经过 腓尼基人 的拼音化 和 广泛传播 终于来到了 希腊   ​   添加图片注释,不超过 140 ...

  10. [oeasy]python0070_ 字体样式_下划线_中划线_闪动效果_反相_取消效果

    字体样式 回忆上次内容 m 可以改变字体样式 0-10 之间设置的都是字体效果 0 复原 1 变亮 2 变暗 从3到10 又是什么效果 呢?? 真的可以blink闪烁吗? 3m 3m 实现斜体字的效果 ...