阿里Java一面:volatile原理分析,你确定你能答出来

【Java并发编程】10. 一文搞懂volatile 由浅入深,直击痛点 今天闲来无事跟同事小麦大叔闲聊, SoWhat:麦叔听说你偷偷面阿里啦,面的咋样? 小麦大叔: 一面挺简单的,主要问了一些基本的数据结构跟算法,还问了下 HashMap的十大常见基本问题。我都答案上来了,还问了我JDK7环,幸亏你那个HashMap环绘制的牛逼,我答的不错就让我准备二面了。 SoWhat:二面类? 小麦大叔:二面问了我一些JVM的问题,问我对于JVM内存模型的理解,还有GC的常见... 阅读详情

介绍

使用 volatile 修饰的变量是线程共享的全局变量,是轻量级锁的一种表现形式,因为不需要线程上线文切换和调度这些操作,效率杠杠的,但是不能保证原子性,并发场景下要小心使用,比如:多个线程同时执行 i++ 是有问题的。

volatile 的 Demo 代码:

/**
 * 单例模式(懒汉式)
 * @date:2020 年 7 月 14 日 上午 9:48:24
 */
public class Singleton {
    public static volatile Singleton instance = null;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (instance == null) {     //代码 1
            synchronized (instance) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Singleton 对象是使用 volatile 修饰,所有线程都可见此对象,即有可能被多个线程同时访问此对象,比如有 A 和 B 两条线程同时进入代码 1,如果 B 线程获取锁进行对象初始化,A 线程自旋等待拿锁,B 线程完成初始化对象后释放锁,然后 A 线程获取锁后判断对象是否为 null,为了避免再次初始化对象节约了系统开销,所以此处必须使用双重校验 null。

特性及原理

可见性

任意一个线程修改了 volatile 修饰的变量,其他线程可以马上识别到最新值。实现可见性的原理如下。

步骤 1:修改本地内存,强制刷回主内存。

阿里Java一面:volatile原理分析,你确定你能答出来

 

步骤 2:强制让其他线程的工作内存失效过期。

阿里Java一面:volatile原理分析,你确定你能答出来

 

步骤 3:其他线程重新从主内存加载最新值。

阿里Java一面:volatile原理分析,你确定你能答出来

 

单个读/写具有原子性

单个 volatile 变量的读/写(比如 vl=l)具有原子性,复合操作(比如 i++)不具有原子性,Demo 代码如下:

public class VolatileFeaturesA {
    private volatile long vol = 0L;

    /**
     * 单个读具有原子性
     * @date:2020 年 7 月 14 日 下午 5:02:38
     */
    public long get() {
        return vol;
    }

    /**
     * 单个写具有原子性
     * @date:2020 年 7 月 14 日 下午 5:01:49
     */
    public void set(long l) {
        vol = l;
    }

    /**
     * 复合(多个)读和写不具有原子性
     * @date:2020 年 7 月 14 日 下午 5:02:24
     */
    public void getAndAdd() {
        vol++;
    }

}

互斥性

同一时刻只允许一个线程操作 volatile 变量,volatile 修饰的变量在不加锁的场景下也能实现有锁的效果,类似于互斥锁。上面的 VolatileFeaturesA.java 和下面的 VolatileFeaturesB.java 两个类实现的功能是一样的(除了 getAndAdd 方法)。

public class VolatileFeaturesB {
    long vol = 0L;

    /**
     * 普通写操作
     * @date:2020 年 7 月 14 日 下午 8:18:34
     * @param l
     */
    public synchronized void set(long l) {  
        vol = l;
    }

    /**
     * 加 1 操作
     * @author songjinzhou
     * @date:2020 年 7 月 14 日 下午 8:28:25
     */
    public void getAndAdd() {
        long temp = get();
        temp += 1L;
        set(temp);
    }

    /**
     * 普通读操作
     * @date:2020 年 7 月 14 日 下午 8:33:00
     * @return
     */
    public synchronized long get() {
        return vol;
    }
}

部分有序性

JVM 是使用内存屏障来禁止指令重排,从而达到部分有序性效果,看看下面的 Demo 代码分析自然明白为什么只是部分有序:

//a、b 是普通变量,flag 是 volatile 变量
int a = 1;            //代码 1
int b = 2;            //代码 2
boolean flag = true;  //代码 3
int a = 3;            //代码 4
int b = 4;            //代码 5

PS:因为 flag 变量是使用 volatile 修饰,则在进行指令重排序时,不会把代码 3 放到代码 1 和代码 2 前面,也不会把代码 3 放到代码 4 或者代码 5 后面。但是指令重排时代码 1 和代码 2 顺序、代码 4 和代码 5 的顺序不在禁止重排范围内,比如:代码 2 可能会被移到代码 1 之前。

内存屏障类型分为四类。

1. LoadLoadBarriers

指令示例:LoadA —> Loadload —> LoadB

此屏障可以保证 LoadB 和后续读指令都可以读到 LoadA 指令加载的数据,即读操作 LoadA 肯定比 LoadB 先执行。

2. StoreStoreBarriers

指令示例:StoreA —> StoreStore —> StoreB

此屏障可以保证 StoreB 和后续写指令可以操作 StoreA 指令执行后的数据,即写操作 StoreA 肯定比 StoreB 先执行。

3. LoadStoreBarriers

指令示例: LoadA —> LoadStore —> StoreB

此屏障可以保证 StoreB 和后续写指令可以读到 LoadA 指令加载的数据,即读操作 LoadA 肯定比写操作 StoreB 先执行。

4. StoreLoadBarriers

指令示例:StoreA —> StoreLoad —> LoadB

此屏障可以保证 LoadB 和后续读指令都可以读到 StoreA 指令执行后的数据,即写操作 StoreA 肯定比读操作 LoadB 先执行。

实现有序性的原理:

如果属性使用了 volatile 修饰,在编译的时候会在该属性的前或后插入上面介绍的 4 类内存屏障来禁止指令重排,比如:

  • 在 volatile 写操作的前面插入 StoreStoreBarriers 保证 volatile 写操作之前的普通读写操作执行完毕后再执行 volatile 写操作。
  • 在 volatile 写操作的后面插入 StoreLoadBarriers 保证 volatile 写操作后的数据刷新到主内存,保证之后的 volatile 读写操作能使用最新数据(主内存)。
  • 在 volatile 读操作的后面插入 LoadLoadBarriers 和 LoadStoreBarriers 保证 volatile 读写操作之后的普通读写操作先把线程本地的变量置为无效,再把主内存的共享变量更新到本地内存,之后都使用本地内存变量。

volatile 读操作内存屏障:

阿里Java一面:volatile原理分析,你确定你能答出来

 

volatile 写操作内存屏障:

阿里Java一面:volatile原理分析,你确定你能答出来

 

3.使用场景

状态标志,比如布尔类型状态标志,作为完成某个重要事件的标识,此标识不能依赖其他任何变量,Demo 代码如下:

public class Flag {
    //任务是否完成标志,true:已完成,false:未完成
    volatile boolean finishFlag;

    public void finish() {
        finishFlag = true;
    }

    public void doTask() { 
        while (!finishFlag) { 
            //keep do task
        }
    }
}

一次性安全发布,比如:著名的 double-checked-locking,demo 代码上面已贴出。

开销较低的读,比如:计算器,Demo 代码如下。

/**
 * 计数器
 */
public class Counter {
    private volatile int value;
    //读操作无需加锁,减少同步开销提交性能,使用 volatile 修饰保证读操作的可见性,每次都可以读到最新值 
    public int getValue() {
        return value; 
    }
    //写操作使用 synchronized 加锁,保证原子性
    public synchronized int increment() {
        return value++;
    }
}

最后

觉得不错的小伙伴记得转发关注哦,后续会持续更新精选技术文章!

深入瑞芯微ISP生态:手把手配置RK3588上的RKAIQ Server并与Windows端RKISP Tuner联调 本文详细介绍了如何在RK3588平台上配置RKAIQ Server并与Windows端的RKISP Tuner进行联调,以实现高效的ISP调优。从环境准备、服务部署到实战调试,涵盖了IMX415相机适配等关键步骤,帮助开发者快速掌握瑞芯微ISP生态的核心技术。 阅读详情

相关推荐

戴尔笔记本装Ubuntu 20.04,别急着分区!先搞定这个BIOS设置(Intel RST避坑指南)

本文详细介绍了在戴尔笔记本上安装Ubuntu 20.04时遇到的Intel RST技术兼容性问题及解决方案。通过安全切换至AHCI模式,避免安装过程中找不到硬盘的常见问题,并提供双系统分区策略和安装后的优化建议,确保Ubuntu与Windows 10双系统稳定运行。

weixin_31315567的博客 273

万字长文详解 volatile 关键字。

volatile 这个关键字大家都不陌生,这个关键字一般通常用于并发编程中,是 Java 虚拟机提供的轻量化同步机制,你可能知道 volatile 是干啥的,但是你未必能够清晰明了的知道 volatile 的实现机制,以及 volatile 解决了什么问题,这篇文章我就来带大家解析一波。 volatile 能够保证共享变量之间的 可见性,共享变量是存在堆区的,而堆区又与内存模型有关,所以我们要聊 volatile ,就需要首先了解一下 Java 内存模型。Java 中的内存模型是 JVM 提供的,而 JV

m0_50180963的博客 404

AF驱动调试日志全解析:从配置到问题排查

本文全面解析AF驱动调试日志的配置、抓取与分析方法。从内核驱动与HAL层配置入手,确保日志正常输出,并详细解读开机初始化、马达识别、I2C通信等关键日志节点。通过多个实战案例,如对焦失败、前摄无功能、参数不生效及I2C报错等,系统性地展示了如何利用日志定位并解决AF对焦问题,是摄像头模组开发与调试的实用指南。

weixin_28285943的博客 307

万字长文详细搞懂 volatile 关键字

volatile 这个关键字大家都不陌生,这个关键字一般通常用于并发编程中,是 Java 虚拟机提供的轻量化同步机制,你可能知道 volatile 是干啥的,但是你未必能够清晰明了的知道 volatile 的实现机制,以及 volatile 解决了什么问题,这篇文章我就来带大家解析一波。 volatile 能够保证共享变量之间的 可见性,共享变量是存在堆区的,而堆区又与内存模型有关,所以我们要聊 volatile ,就需要首先了解一下 Java 内存模型。Java 中的内存模型是 JVM 提供的,而 JVM

程序员cxuan的个人主页 5156

一文搞懂 RC Correlation Scale Factor 的生成与应用

pre-route 用的是统计估算模型,post-route 用的是详细布线提取,signoff 用的是第三方 QRC 或 StarRC——三个工具,三套参数体系,结果自然天差地别。不同 RC corner(rc_worst/rc_best/rc_typical)对应不同的工艺角和温度环境,每个 corner 的 R/C 偏差比例不同,必须分别生成和应用各自的 scale factor。别被名字骗了,这个工具专门干一件事——统计拟合两组 SPEF 之间的偏差,自动推荐最优 scaling factor。

weixin_47770727的博客 563

地平线RDKX3初始配置与USB无线网卡

地平线X3无线网卡配置

Richard_Mei的博客 4082

java中的Volatile关键字(成员变量修饰符)

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。 Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。 这样当多个线程同时与某个对象交

shijinupc的专栏 9300

招财牛猫|股社区|猫笔刀公众号历史文章13-21年(含评论),投资内容 收藏学习

招财大牛猫|股社区|猫笔刀公主号历史文章13-21年(含评论)

ZhaoCaiDaNiuMao的博客 7244

其他:volatile的原理解析

在看AtomicInteger代码的时候,看到了它的原始是这么定义的 private volatile int value;,在unsafe类中有这几种原生的方法 var5 = this.getIntVolatile(var1, var2); var6 = this.getLongVolatile(var1, var2); var5 = this.getObjectVolat...

maoyeqiu的专栏 536

ESP32-C3微型9轴感知模块的硬件工程实践

在嵌入式系统小型化趋势下,低功耗微控制器与多传感器融合成为智能终端的基础技术路径。其核心原理在于芯片能效比、射频合规性与电源噪声抑制的协同优化,技术价值体现在降低认证门槛、提升EMC鲁棒性及保障MEMS传感器精度。典型应用场景包括可穿戴设备、微型无人机姿态控制和工业边缘传感节点。本文围绕ESP32-C3平台展开,深入解析QFN封装选型逻辑、同步降压电源设计、LSM9DS1九轴校准策略等关键环节,覆盖FCC/CE认证规避、USB-C接口EMC防护等高频工程痛点。

weixin_42607969的博客 371

302.QoS实现工具之MQC

QoS 技术可以对网络中报文进行分类处理,根据优先级提供不同的差分服务,如何实现这种差分服务呢?我们有一种强大的配置方法 - 模块化 QoS 命令行 MQC(Modular QoS Command-Line)。下面就来介绍一下 MQC。

迷逝 1397

Java程序员面试必备:Volatile全方位解析

volatile是Java程序员必备的基础,也是面试官非常喜欢问的一个话题,本文跟大家一起开启volatile学习之旅,如果有不正确的地方,也麻烦大家指出哈,一起相互学习~github 地址volatile关键字是Java虚拟机提供的的最轻量级的同步机制,它作为一个修饰符出现,用来修饰变量,但是这里不包括局部变量哦。我们来看个demo吧,代码如下: 运行结果:可以发现线程t2,虽然把stop设置为true了,但是线程t1对t2的stop变量视而不可见,因此,它一直在死循环running中。如果给变量st

the shy 848

国科大学习资料--机器学习方法与应用(叶齐祥)-期末考试题整理

国科大学习资料–机器学习方法与应用-期末考试题整理 ============================================================================================================================================================================================ =======================================

无名何许人的博客 2852

面试:为了进阿里,重新翻阅了Volatile与Synchronized

该系列文章收录在公众号【Ccww技术博客】,原创技术文章早于博客推出 在深入理解使用Volatile与Synchronized时,应该先理解明白Java内存模型 (Java Memory Model,JMM) Java内存模型(Java Memory Model,JMM) Java内存(JMM)模型是在硬件内存模型基础上更高层的抽象,它屏蔽了各种硬件和操作系统对内存访问的差异性,从而实现让Java程序在各种平台下都能达到一致的并发效果。 JMM的内部工作机制 主内存:存储共享的变量值(实例变量和.

Ccww_的博客 3380

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

三面阿里java后台开发岗总结:进阿里必看这份究极面试文档

前言 最近原来实习时候的Boss联系我,说他跳槽到了阿里,问我有没有兴趣面一个Java后台开发岗位。 考虑到我只工作了一年,现在去阿里肯定要降薪,因此也没有太强烈的意愿。但出于提升自我的角度考虑,参加了面试。 一面(电话面试一小时) 首先做一个简单的自我介绍,主要包括学校经历和工作经历。我工作经历只有一年,大部分时间都是在做产品设计和UI/UX Design,因此隔着电话都能感受到面试官的shock。 Java基础。自动拆装箱如何实现,String,StringBuffer,StringBuild

JavaJIAMIN的博客 1283

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

多亏阿里学长的这份Java多线程笔记,让我轻松拿下阿里一面

内推进阿里,面试之前阿里学长给了一份Java多线程笔记,让我轻松拿下阿里一面。 以下这些技术点都是阿里学长的全解析笔记中总结的内容: 笔记内容介绍: 由于笔记内容过多,因此为了避免影响到大家的阅读体验,在此只以截图展示部分内容,详细完整版的看文末有免费的获取方式! 基础篇 进程与线程基本概念 Java多线程入门类和接口 线程组和线程优先级 Java线程的状态及主要转化方法 Java线程间的通信 原理篇 Java内存模型基础知识 重排序与hap...

Java6888的博客 228

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

【并发编程】volatile实现原理解析

本文深入浅出讲解了什么是volatile与volatile 的使用场景,对什么是 happens-before 关系进行不同场景分析,最后分析volatile 可见性(lock指令)与禁止重排(内存屏障)的原理,最后给出两道常见面试题“volatile 和 synchronized 的关系”、“单例双重检查锁模式中为什么要 volatile”作为本文扩展。

小明的Java问道之路 2602

【阿里面试系列】并发编程之Volatile的作用及原理

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34007886的博客 125

阿里面试官让我讲讲volatile,我直接从HotSpot开始讲起,一套组合拳拿下面试

对于Java开发者而言,关于底层知识,我们一般当做黑盒来进行使用,不需要去打开这个黑盒。 但随着目前程序员行业的发展,我们有必要打开这个黑盒,去探索其中的奥妙。 本篇系列文章,将带你一起探索底层黑盒的奥秘之处。

爱敲代码的小黄 2286

面经:阿里Java后台开发

点击“蓝字”关注我们获得资讯/干货/内推最近原来实习时候的Boss联系我,说他跳槽到了阿里,问我有没有兴趣面一个Java后台开发岗位。考虑到我只工作了一年,现在去阿里肯定要降薪,因...

JAVA高级架构 573

【面经】2018阿里java实习生一面

我是上周通过boss直聘的内推人内推的,然后过了三天就收到了电话。。。就记得这些点了,但是有的不是单纯问知识,会用一些实例去提问,面试官非常nice,人很随和,最后还给我说了谢谢~~1、介绍自己:要突出技能2、项目介绍:要突出难点及解决方案3、网络:子网掩码是什么?有什么作用三次握手(为什么二次握手不行)time waitTCP协议和UDP区别有没有什么网络项目4、数据库事务 ACID 隔离特性与...

zlx312的博客 6129

分析Volatile的作用及底层实现原理,面试问一点都不慌!

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了《Java中高级核心知识全面解析》小米商场项目实战,别再担心面试没有实战项目:网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)一个人可以走的很快,但一群人才能走的更远!

2401_84418948的博客 1001

java p7要求_阿里P7第一面:Java基础,必须全部答对

说好了面试系列已经完结了,结果发现还是真香,嗯,以为我发现我的Java基础都没写,所以这个就算作续集了,续集第一篇请各位收好。说说进程和线程的区别?进程是程序的一次执行,是系统进行资源分配和调度的独立单位,他的作用是是程序能够并发执行提高资源利用率和吞吐率。由于进程是资源分配和调度的基本单位,因为进程的创建、销毁、切换产生大量的时间和空间的开销,进程的数量不能太多,而线程是比进程更小的能独立运行的...

weixin_42405852的博客 742

阿里巴巴java技术岗三面分享

阿里巴巴java技术岗三面分享 今天花时间整理了阿里巴巴Java岗技术三面的资料,分给大家做参考,祝大家都能找到好工作!加油! 一面 1、自我介绍,讲讲求职意向和擅长的技能 2、Tomcat的基本架构是什么? 3、JVM调优,工作中怎么用,GC算法和回收策略有哪些 4、Java中线程池是如何实现的? 创建线程池的几个核心构造参数是什么? 5、Volatile和Synchronize的区别? 6、GC的机制是什么?垃圾回收器的基本原理是还说呢么?是否可以立即回收内存?怎么样主动的通知JVM

weixin_46577306的博客 2216

Volatile关键字以及底层原理

如下就不会进行指令重排序。3.voletle规则: volatle变量的写,先发生于读,这保证了volatle变量的可见性,简单的理解就是,volatle变量在每次被线程访问时,都强迫从主内存中读该变量的值,而当该变量发生变化时,又会强迫将最新的值刷新到主内存,任何时刻,不同的线程总是能够看到该变量的最新值。4.线程启动规则: 线程的start()方法先于它的每一个动作,即如果线程A在执行线程B的star方法之前修改了共享变量的值,那么当线程B执行start方法时,线程A对共享变量的修改对线程B可见。

m0_61095983的博客 651

来一起看看阿里的Java开发面试题吧

这些常见的基础面试题,你都会了吗

程序员波特 756
上一篇: 面试官:CAS和AQS底层原理了解?我:一篇文章堵住你的嘴
下一篇: synchronized相关面试题,你接得住吗?
爱玛士
博客等级 码龄7年 720粉丝 253原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值