Java岗面试题--Java并发(volatile 专题)

news2024/9/30 19:34:38

目录

  • 1. 面试题一:谈谈 volatile 的使用及其原理
    • 补充:内存屏障
    • volatile 的原理
  • 2. 面试题二:volatile 为什么不能保证原子性
  • 3. 面试题三:volatile 的内存语义
  • 4. 面试题四:volatile 的实现机制
  • 5. 面试题五:volatile 与锁的对比

1. 面试题一:谈谈 volatile 的使用及其原理

volatile 关键字是用来保证有序性和可见性的。

我们所写的代码,不一定是按照我们自己书写的顺序来执行的,编译器会做重排序,CPU 也会做重排序的,这样做是为了了减少流水线阻塞,提高 CPU 的执行效率。这就需要有一定的顺序和规则来保证,不然程序员自己写的代码都不不知道对不对了,所以有 happens-before 规则。

其中有条就是 volatile 变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作、有序性实现的是通过插入内存屏障来保证的。

被 volatile 修饰的共享变量量,就具有了以下两点特性:

  1. 保证了不同线程对该变量操作的内存可见性;
  2. 禁止指令重排序。

补充:内存屏障

从 CPU 层面来了解一下什么是内存屏障。

CPU 的乱序执行,本质还是 CPU 多核心、CPU 高速缓存。存在多个缓存的时候,就必须通过缓存一致性协议(MESI)来避免数据不一致的问题,而这个通讯的过程就可能导致乱序访问的问题,也就是运行时的内存乱序访问。

现在的 CPU 架构都提供了内存屏障功能,在 x86 的 CPU 中,实现了相应的内存屏障,写屏障(Store Barrier)、读屏障(Load Barrier)和全屏障(Full Barrier),主要的作用是:

  • 防止指令之间的重排序;
  • 保证数据的可见性。

volatile 的原理

在 JVM 底层 volatile 是采用「内存屏障」来实现的。当我们观察加入 volatile 关键字和没有加入 volatile 关键字时所生成的汇编代码会发现,加入 volatile 关键字时,会多出一个 lock 前缀指令,lock 前缀指令实际上相当于一个内存屏障,内存屏障会提供三个功能:

  1. 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
  2. 它会强制将对缓存的修改操作立即写入主存;
  3. 如果是写操作,它会导致其他CPU中对应的缓存行无效。

会引发两件事情:

  1. 将当前处理器缓存行的数据写回到系统内存;
  2. 这个写回内存的操作会使得在其他处理器缓存了该内存地址无效;

什么意思呢?意思就是说当一个共享变量被 volatile 修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值,这就保证了可见性。
在这里插入图片描述
在这里插入图片描述

2. 面试题二:volatile 为什么不能保证原子性

一个变量 i 被 volatile 修饰,两个线程想对这个变量修改,都对其进行自增操作也就是 i++,i++ 的过程可以分为三步,首先获取 i 的值,其次对 i 的值进行加1,最后将得到的新值写会到缓存中。

线程 A 首先得到了 i 的初始值100,但是还没来得及修改,就阻塞了,这时线程 B 开始了,它也得到了 i 的值,由于 i 的值未被修改,即使是被 volatile 修饰,主存的变量还没变化,那么线程 B 得到的值也是100,之后对其进行加 1 操作,得到101后,将新值写入到缓存中,再刷入主存中。根据可见性的原则,这个主存的值可以被其他线程可见。

问题来了,线程 A 已经读取到了 i 的值为100,也就是说读取的这个原子操作已经结束了,所以这个可见性来的有点晚,线程 A 阻塞结束后,继续将 100 这个值加 1,得到101,再将值写到缓存,最后刷入主存,所以即便是 volatile 具有可见性,也不能保证对它修饰的变量具有原子性。

测试案例:

/**
 * 实体类,观察num值的可见性,此时没有volatile
 */
class Volatile {
    // volatile int num = 0; 加上volatile关键字
    int num = 0;  // 不加volatile关键字
    public void addTo60() {
        this.num = 60;
    }
}

//测试类
public class test {

    public static void main(String[] args) {
        //测试可见性
        seeVolatileOk();
    }

    /**
     * aaa线程修改num值为60后,main线程拿到的num=0,死循环。说明线程之间共享变量不可见。
     */
    private static void seeVolatileOk() {
        Volatile v = new Volatile();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t come in ");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            v.addTo60();
            System.out.println(Thread.currentThread().getName() + "\t updated num value:" + v.num);

        }, "aaa").start();
        while (v.num==0){

        }
        System.out.println(Thread.currentThread().getName() + "\t mission is over,updated num value:" + v.num);
    }
}

3. 面试题三:volatile 的内存语义

  1. 写内存语义:当写一个 volatile 变量时,JMM 会把该线程本地内存中的共享变量的值刷新到主内存;
  2. 读内存语义:当读一个 volatile 变量时,JMM 会把该线程本地内存置为无效,使其从主内存中读取共享变量。

4. 面试题四:volatile 的实现机制

为了实现 volatile 的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。内存屏障插入策略非常保守,但它可以保证在任意处理器平台,任意的程序中都能得到正确的 volatile 内存语义。

  1. 在每个volatile写操作的前面插入一个 StoreStore 屏障;
  2. 在每个volatile写操作的后面插入一个 StoreLoad 屏障;
  3. 在每个volatile读操作的后面插入一个 LoadLoad 屏障;
  4. 在每个volatile读操作的后面插入一个 LoadStore 屏障。

5. 面试题五:volatile 与锁的对比

volatile 仅仅保证对单个 volatile 变量的读/写具有原子性,而锁的互斥执行的特性可以确保对整个临界区代码的执行具有原子性。在功能上锁比 volatile 更强大,在可伸缩性和执行性能上 volatile 更有优势。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/374917.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用c语言模拟实现常用字符串函数

目录 一.常用字符串函数介绍 1.strlen 2. strcpy 3.strcmp 4.strcat 5.strstr 二.模拟实现常用字符串函数 1.strlen 2.strcpy 3.strcmp 4.strcat 5.strstr 一.常用字符串函数介绍 1.strlen 字符串strlen是用来求字符串长度的,我们可以打开cpp网站查看有关…

浅谈模型评估选择及重要性

作者:王同学 来源:投稿 编辑:学姐 模型评估作为机器学习领域一项不可分割的部分,却常常被大家忽略,其实在机器学习领域中重要的不仅仅是模型结构和参数量,对模型的评估也是至关重要的,只有选择那…

vector迭代器失效与深浅拷贝问题

目录 1、vector迭代器失效问题 1.1、insert迭代器失效 扩容导致野指针 意义变了 官方库windows下VS和linux下对insert迭代器失效的处理 1.2、erase迭代器失效 官方库windows下VS和linux下对erase迭代器失效的处理 1.3、迭代器失效总结 2、深浅拷贝问题 1、vector迭…

GeoServer发布数据进阶

GeoServer发布数据进阶 GeoServer介绍 GeoServer是用于共享地理空间数据的开源服务器。 它专为交互操作性而设计,使用开放标准发布来自任何主要空间数据源的数据。 GeoServer实现了行业标准的 OGC 协议,例如网络要素服务 (WFS)…

Java【优先级队列】模拟实现 + 【PriorityQueue】介绍

文章目录一、什么是优先级队列二、模拟实现1, 实现堆的基本操作1.1, 创建堆1.2.1, 向下调整1.2, 堆的插入1.2.1, 向上调整1.2, 堆的删除2, 实现优先级队列2.1, offer -- 插入数据2.1, poll -- 删除数据三、Java提供的PriorityQueue1, PriorityQueue说明2, 使用PriorityQueue2.1…

【Linux】安装Tomcat教程

目录 1.上传安装包 2.解压安装包 3.启动Tomcat 4.查看启动日志 5.查看进程 6.开放端口 7.停止Tomcat 1.上传安装包 使用FinalShell自带的上传工具将Tomcat的二进制发布包上传到Linux(与前面上传JDK安装包步骤 一致)。 2.解压安装包 将上传上来的安装包解压到指定目录…

2023年想跳槽,什么类型的人才需求最多?

某招聘网站资深HR对此表示:纵观当前招聘市场,无论是比较火爆的互联网行业还是传统行业,技能型人才都是最受欢迎的人才之一;那些拥有职场一技之能的跳槽者往往跳的结果更好,包括薪酬水平和发展空间、重视程度等。 那选择…

一个更适合Java初学者的轻量级开发工具:BlueJ

Java是世界上最流行的编程语言之一,它被广泛用于从Web开发到移动应用的各种应用程序。大部分Java工程师主要是用IDEA、Eclipse为主,这两个开发工具由于有强大的能力,所以复杂度上就更高一些。如果您刚刚开始使用Java,或者您更适合…

如何简化跨网络安全域的文件发送流程,大幅降低IT人员工作量?

为什么要做安全域的隔离? 随着企业数字化转型的逐步深入,企业投入了大量资源进行信息系统建设,信息化程度日益提升。在这一过程中,企业也越来越重视核心数据资产的保护,数据资产的安全防护成为企业面临的重大挑战。 …

自动化测试学习步骤及路线(超详细)

随着测试行业的不断发展,目前企业对测试人员要求越来越高,仅仅响应需求的功能测试人员基本饱和或是留给了校招生。而对于社招渠道的应聘者,企业越来越多地要求有一定的自动化或是代码经验,能解决工作过程中遇到的问题,…

ledcode【用队列实现栈】

目录 题目描述: 解析题目 代码解析 1.封装一个队列 1.2封装带两个队列的结构体 1.3封装指向队列的结构体 1.4入栈函数实现 1.5出栈函数实现 1.6取栈顶数据 1.7判空函数实现 题目描述: 解析题目 这个题我是用c语言写的,所以队列的pu…

魔兽世界WoW注册网站搭建——-Liunx

问题背景哎 搭建了一个魔兽3.35(纯洁版)每当同学朋友要玩的时候我都直接worldserver上面打一个命令随之出现朋友的朋友也要玩想了想还是要有一个网站原本以为吧单机版里面网页的IP数据库改下可以了结果PHP报错了Unknown column sha_pass_hash in field l…

学校AI视频行为分析监测系统 opencv

学校AI视频行为分析监测系统通过pythonopencv网络模型AI视频分析技术,学校AI视频行为分析监测算法对学校区域人员打架行为识别、跌倒行为识别、翻墙识别、人员聚众识别、攀高识别、抽烟行为等进行智能识别预警。OpenCV的全称是Open Source Computer Vision Library&…

C#专栏目录(长期更新)

文章目录C# 基础C#进阶C#应用WPF基础WPF 3D小游戏C# 基础 1996年,微软用年薪三百万美刀的价格从Borland挖来了大神海尔斯伯格,开始了J开发,用以对抗Java。但SUN公司认为此举违反了Java开发平台的中立性,对微软提出诉讼。C#正是在…

RBAC 权限模型介绍

RBAC 权限: 一、关系: 这基于角色的访问控制的结构就叫RBAC结构。 二、RBAC 重要对象: 用户(Employee):角色施加的主体;用户通过拥有某个或多个角色以得到对应的权限。角色(Role&…

SQL零基础入门学习(十三)

上一篇(SQL零基础入门学习(十二)) SQL 视图(Views) 视图是可视化的表。 SQL CREATE VIEW 语句 在 SQL 中,视图是基于 SQL 语句的结果集的可视化的表。 视图包含行和列,就像一个…

jsp+servlet+javabean新闻发布系统

技术:Java、JSP等摘要:近年来,Internet技术得到迅速的发展,已经成为计算机产业的一个技术热点。促成Internet高速发展的因素之一就是Web技术。Web技术的发展使得那些具有交互动态页面、有条理的数据库查询、丰富信息内容的页面成为最吸引人的网页。浏览W…

MVCC 当前读 快照读 RC read view RR下事务更新不会丢失

MVCC(multi-version-concurrent-control) MVCC是行锁的一个变种,但MVCC在很多情况下它避免了加锁。不是buffer块,而是buffer中的记录行。 MVCC (Multi-Version Concurrency Control) (注:与MVCC相对的,是基于锁的并发控制&#x…

SVIP优先办理服务-课后程序(JAVA基础案例教程-黑马程序员编著-第八章-课后作业)

【案例8-2】 Svip优先办理服务 【案例介绍】 1.任务描述 在日常工作生活中,无论哪个行业都会设置一些Svip用户,Svip用户具有超级优先权,在办理业务时,Svip用户具有最大的优先级。 本案例要求编写一个模拟Svip优先办理业务的程…

350-401-拖图题1

拖图题 QoS;policing:dropped,no delay;shaping:buffers,delay;policing有TCP和no。shaping有buffer缓冲器和delay延迟;警察安全不丢失,定型过多延迟又延迟 traffic policing:流量监管 causes TCP retran…