当前位置: 首页 > news >正文

Java内存模型与volatile

Java内存模型

Java内存模型Java Memory Model,简称JMM,本身是一种抽象的概念并不真实存在它仅仅描述的是一组约定或规范,通过这组规范定义了程序中(尤其是多线程)各个变量的读写访问方式并决定一个线程对共享变量的写入何时以及如何变成对另一个线程可见,关键技术点都是围绕多线程的原子性可见性有序性展开的。

JMM规范下,三大特性

  • 原子性
  • 可见性
  • 有序性
原子性

指一个操作是不可中断的,即多线程环境下,操作不能被其他线程干扰。

可见性
  • ​ Java中普通的共享变量不保证可见性,因为数据修改被写入内存的时机是不确定的,多线程并发下很可能出现"脏读"。

  • 每个线程都有自己的工作内存,线程自己的工作内存中保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取,赋值)都必需在线程自己的工作内存中进行,而不能够直接读写主内存中的变量。

在这里插入图片描述

有序性
  • 对于一个线程的执行代码而言,我们总是习惯性认为代码的执行总是从上到下,有序执行。 但为了提供性能,编译器处理器通常会对指令序列进行重新排序。

  • 指令重排可以保证串行语义一致,但没有义务保证多线程间的语义也一致,即可能产生"脏读"。

总结
  • 我们定义的所有共享变量都储存在物理主内存中
  • 每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)
  • 线程对共享变量所有的操作都必须先在线程自己的工作内存中进行后写回主内存,不能直接从主内存中读写(不能越级)
  • 不同线程之间也无法直接访问其他线程的工作内存中的变量,线程间变量值的传递需要通过主内存来进行(同级不能相互访问)

volatile

关键字,保证不同线程对这个变量进行操作时的可见性,即变量一旦改变所有线程立即可见,指令禁重排,不能保证原子性。

  • 可见性
  • 有序性

volatile凭什么可以保证可见性和有序性???

内存屏障 (Memory Barriers / Fences),是一种屏障指令,它使得CPU或编译器对屏障指令的前和后所发出的内存操作执行一个排序的约束。也叫内存栅栏或栅栏指令。

  • 阻止屏障两边的指令重排序
  • 写数据时加入屏障,强制将线程私有工作内存的数据刷回主物理内存
  • 读数据时加入屏障,线程私有工作内存的数据失效,重新到主物理内存中获取最新数据
屏障类型

在这里插入图片描述

写屏障
  • 在每个 volatile 写操作的前⾯插⼊⼀个 StoreStore 屏障

  • 在每个 volatile 写操作的后⾯插⼊⼀个 StoreLoad 屏障

读屏障
  • 在每个 volatile 读操作的后⾯插⼊⼀个 LoadLoad 屏障
  • 在每个 volatile 读操作的后⾯插⼊⼀个 LoadStore 屏障
volatile可见性

volatile关键字保证可见性,意味着∶

  • 对一个volatile修饰的变量进行读操作的话,总是能够读到这个变量的最新的值,也就是这个变量最后被修改的值

  • 一个线程修改了volatile修饰的变量的值的时候,那么这个变量的新的值,会立即刷新回到主内存中

  • 一个线程去读取 volatile 修饰的变量的值的时候,该变量在工作内存中的数据无效,需要重新到主内存去读取最新的数据

volatile有序性
  • volatile 写之前的操作,都禁止重排序到volatile之后
  • volatile读之后的操作,都禁止重排序到volatile之前
  • volatile 写之后的操作,都禁止重排序到volatile之前

相关文章:

  • LIO-SAM中的mapOptmization
  • Pandas数据处理可视化
  • NA of optical fiber(光纤的数值孔径)
  • 花了整整一天,总结了C语言所有常用的文件操作
  • 2022 年十大 Python Web 开发框架
  • Go语言学习(五)-- 函数和闭包
  • 【数据结构】链表其实并不难 —— 手把手带你实现单链表
  • LeetCode每日一题——754. 到达终点数字
  • 有一个是对的,就是坚持去做难的事情。
  • httpClient同步、异步性能对比
  • 吴峰光杀进 Linux 内核
  • 朋友离职了,一周面试了20多场,我直呼内行
  • 创建 MQTT 连接时如何设置参数?
  • C#基础知识
  • 云原生之快速使用Nacos Spring Cloud
  • 什么是GPIO的推挽输出和开漏输出
  • Java 模拟实现 定时器 和 线程池
  • 笔记,正则表达式里的元字符
  • kubernetes 生成认证文件
  • LINUX系统搭建FTP服务器--操作步骤