icode icode
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

iqqcode

保持对技术的探索实践与热爱
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaSE

    • 面向对象

    • 常用API

    • 集合类

    • 多线程

      • Thread

      • JUC

        • JUC包下的常用工具类
        • JUC包下常用的辅助类
        • 阻塞队列,同步队列
        • Java内存模型JMM详解
        • volatile
          • CAS自旋
          • CAS与volatile无锁解决并发
          • AQS
          • 线程池
          • Future接口
      • JDK8新特性

      • IO流

      • JVM

    • JavaWeb

    • JavaEE

    • JavaTopic

    • 设计模式

    • 计算机基础

    • Java后端
    • JavaSE
    • 多线程
    • JUC
    iqqcode
    2021-06-17
    目录

    volatile

    在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性都牵扯出来,深入地话还可以考察JVM底层实现以及操作系统的相关知识。

    本文以一次假想的面试过程,来深入了解下volitile关键字【本菜鸡还没投简历,准备好被今年20年秋招的毒打了😭】

    【灵魂拷问开始】

    1. 面试官:Java并发这块了解的怎么样?说说你对volatile关键字的理解?
    2. 面试官:能不能详细说下什么是内存可见性,什么又是重排序呢?
    3. 面试官:volatile怎么保证可见性的?多个线程之间的可见性,你能讲一下底层原理是怎么实现的吗?
    4. 面试官:volatile关键字是怎么保证有序性的?
    5. 面试官:volatile能保证可见性和有序性,但是能保证原子性吗?为什么?
    6. 面试官:了解过JMM内存模型吗?简单的讲讲

    到这里,我的眼里已是常含泪水了。不是因为我对代码爱的深沉,而是因为我菜的真诚!

    没事,不就是个破volatile吗?别念了,我学习还不行吗!

    # Q1:请你谈谈对Volatile关键字的理解?

    Volatile是JVM提供的轻量级的同步机制

    1. 保证可见性

    2. 保证有序性,禁止指令重排

    3. 不保证原子性(需要借助synchronized或者CAS)

    小伙子,不错么😊,回答对了 1 + 1,得来点 2 + 2 的难度了

    # Q2:什么是内存可见性,volatile怎么保证多个线程之间的可见性的?

    问题2和问题3讲到的可见性,用JMM来解释的话,本质上是同一个问题。至于有序性和重排序,到问题4再讨论。

    一问到内存的可见性,volatile相关的,直接就把JMM内存模型搬出来好吧。先放图,然后再表演。

    以下是俺个人的回答,有不足或漏洞,欢迎大家更正指出!

    所谓可见性,是指当一条线程修改了共享变量的值,新值对于其他线程来说是可以立即得知的

    每个线程都有自己独立的工作区间,为了匹配CPU的运行速度,他们不会直接从内存中读取数据,而是将数据拷贝一份到CPU缓存中(即每个线程自己的工作内存),他们之间的相互交互,是通过内存来完成的。

    根据JMM内存模型的8大原子操作,每个线程在将数据操作完stroe回主存之前,会加lock指令来锁定内存区域的缓存(缓存行锁定),根据MESI缓存一致性协议,总线通过侦听器发现数据被修改,会立即让其他线程工作内存中不一致的副本立即失效。等到当前线程将更改后的数据write回主存后,立即执行unlock指令。

    此时,其他线程再重新读取更新后的数据,再拷贝到自己的工作内存。总线侦听机制会在总线上检测线程的数据,发现有线程做了更改时准备store回主内存时,它就会立刻将其他线程工作内存中的副本置位无效,然后从新到主存获取更新后的值。

    除了使用 volatile 关键字来保证内存可见性之外,使用synchronized或Lock锁也能保证变量的内存可见性。只是相比而言使用 volatile关键字开销更小,是轻量级的锁。

    这就是内存可见性的原理。

    # Q3:volatile关键字是怎么保证有序性的?

    使用volatile关键字修饰共享变量便可以禁止指令重排序。若用volatile修饰共享变量,在JVM底层volatile是采用“内存屏障”来实现禁止特定类型的处理器重排序。加入volatile关键字时,会多出一个lock前缀指令,lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:

    1. 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

    2. 它会强制将对缓存的修改操作立即写入主存;

    3. 如果是写操作,它会导致其他CPU中对应的缓存行无效。

    JMM具备一些先天的有序性,通过Happens-Before原则就可以保证的一定的有序性。

    # Q4:volatile能保证可见性和有序性,但是能保证原子性吗?为什么?

    volatile关键字不能保证原子性。

    a. 当写一个volatile变量时,JMM会把该线程本地内存中的变量强制刷新到主内存中去;

    b. 这个写会操作会导致其他线程中的缓存无效。

    对于类似i++这样的复合操作,要想保证原子性,只能借助于synchronized、Lock以及并发包下的AtomicInteger的原子操作类。AtomicInteger对基本数据类型的 自增(加1操作),自减(减1操作)、以及加法操作(加一个数),减法操作(减一个数)进行了封装,保证这些操作是原子性操作。

    # 怎样才能保证原子性?

    1. 加锁。synchronized或Lock

    2. CAS无锁算法

    # Q5:了解过JMM内存模型吗?简单的讲讲

    看完这篇👇文章,这道题目就是你的主场。

    👉👈

    看着这张图,直接就巴拉巴拉一顿操作!

    编辑 (opens new window)
    上次更新: 2021/06/27, 10:49:09
    Java内存模型JMM详解
    CAS自旋

    ← Java内存模型JMM详解 CAS自旋→

    最近更新
    01
    匿名内部类
    10-08
    02
    函数式接口
    10-08
    03
    ARouter-Kotlin踩坑
    10-05
    更多文章>
    Theme by Vdoing | Copyright © 2021-2023 iqqcode | MIT License | 备案号-京ICP备2021028793号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×