gball个人知识库
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)

ggball

后端界的小学生
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)
  • 面试

  • 数据库

  • linux

  • node

  • tensorFlow

  • 基础组件

  • 基础知识

    • java集合

    • jvm调优

    • java并发编程

      • 进程与线程
      • 多线程的方法介绍与使用
      • 线程死锁
      • 守护线程与用户线程
      • ThreadLocal了解
      • 什么是多线程并发编程
      • unsafe类了解
      • 伪共享
      • 锁的了解
      • ThreadLocalRandom原理解析
      • LongAdder,LongAccumulator类了解
      • 实践-创建多少线程合适
      • 线程通信——通知与等待
      • 缓存一致性问题
      • 利用Excutors异步执行任务
      • 线程池
      • 线程池操作数据库造成死锁
      • Java 浅拷贝和深拷贝的理解和实现方式
      • java内存模型JMM
        • 主内存
        • 工作内存
      • 锁升级过程
      • io模型
      • 关键字介绍
      • AQS解析
    • java网络编程

    • java8新特性

    • javaAgent

    • java高级

  • 算法与设计模式

  • 分布式

  • 疑难杂症

  • go学习之旅

  • 极客时间

  • 知识库
  • 基础知识
  • java并发编程
ggball
2021-10-08

java内存模型JMM

# 什么是JMM模型

JMM是一组抽象的概念,并不真实存在,他描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段 和构成数组对象的元素)的访问方式。JMM是围绕原子性,有序性、可见性展开的

工作内存和主内存交互图(1-1)

image-20210325215632833

# 主内存

主要存储的是Java实例对象,所有线程创建的实例对象都存放在主内存中,不管该实例 对象是成员变量还是方法中的本地变量(也称局部变量),当然也包括了共享的类信息、常 量、静态变量。由于是共享数据区域,多条线程对同一个变量进行访问可能会发生线程安全问题。

# 工作内存

主要存储当前方法的所有本地变量信息(工作内存中存储着主内存中的变量副本拷贝), 每个线程只能访问自己的工作内存,即线程中的本地变量对其它线程是不可见的,就算是两个线程执行的是同一段代码,它们也会各自在自己的工作内存中创建属于当前线程的本地变量,当然也包括了字节码行号指示器、相关Native方法的信息。注意由于工作内存是每个线程的私有数据,线程间无法相互访问工作内存,因此存储在工作内存的数据不存在线程安 全问题。

# 主内存和工作内存是如何交互的(了解)

首先Java内存模型定义了以下八种操作,来进行主内存和工作内存交互

(1)lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态

(2)unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后

的变量才可以被其他线程锁定

(3)read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存

中,以便随后的load动作使用

(4)load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工

作内存的变量副本中

(5)use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎

(6)assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内

存的变量

(7)store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存

中,以便随后的write的操作

(8)write(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量的值

传送到主内存的变量中

image-20210325220707427

这里如果是多线程的话,就会引起并发的问题了

image-20210325215632833

图1-1中所示是 个双核 CPU 系统架构 ,每个核有自己的控制器和运算器,其中控制器包含一组寄存器和操作控制器,运算器执行算术逻辅运算。每个核都有自己的一级缓存,在有些架构里面还有 个所有 CPU 共享二级缓存。 那么 Java 内存模型里面的工作内存,就对应这里的 Ll 或者 L2 存或者 CPU 寄存器。当一个线程操作共享变量时,它首先从主内存复制共享变量到自己的工作内存,然后对工作内存里的变量进行处理,处理完后将变量值更新到主内存。

那么假如线程A和线程B同时处理一个共享变量,会出现什么情况?我们使用图1-1所示CPU架构,假设线程A和线程B使用不同CPU执行,并且当前两级 Cache都为空,那么这时候由于 Cache的存在,将会导致内存不可见问题,具体看下面的分析

线程A首先获取共享变量X的值,由于两级 Cache都没有命中,所以加载主内存中X的值,假如为0.然后把X=0的值缓存到两级缓存,线程A修改X的值为1,然后将其写入两级 Cache,并且刷新到主内存。

线程A操作完毕后,线程A所在的CPU的两级 Cache内和主内存里面的X的值都是线程B获取X的值,首先一级缓存没有命中,然后看二级缓存,二级缓存命中了所以返回X=1;到这里一切都是正常的,因为这时候主内存中也是X=1.然后线程B修改X的值为2,并将其存放到线程2所在的一级 Cache和共享二级 Cache中最后更新主内存中X的值为2;

到这里一切都是好的。线程A这次又需要修改X的值,获取时一级缓存命中,并且X-=1,到这里问题就出现了,明明线程B已经把X的值修改为了2,为何线程A获取的还是1呢?
1
2
3
4
5

所以要谈到并发编程的三个特性 可见性,原子性,有序性,解决了这三个问题并发问题也就引刃而解

# 并发编程的三个特性

上次更新: 2025/06/04, 15:06:15
Java 浅拷贝和深拷贝的理解和实现方式
锁升级过程

← Java 浅拷贝和深拷贝的理解和实现方式 锁升级过程→

最近更新
01
AIIDE
03-07
02
githubActionCICD实战
03-07
03
windows安装Deep-Live-Cam教程
08-11
更多文章>
Theme by Vdoing
总访问量 次 | 总访客数 人
| Copyright © 2021-2025 ggball | 赣ICP备2021008769号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×

评论

  • 评论 ssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
×