Java内存模型JMM(一)

el/2024/2/25 0:30:32

JMM模型

定义:

Java内存模型(JMM)是一种抽象的概念,不是 JVM内存模型

组成:

  • 线程
  • 工作内存 —— 线程私有的一块内存空间 也称栈空间
  • 主内存 —— **共享内存区域。**所有线程都能访问
  • 总线 —— 完成主内存和工作内存之间的数据交互的桥梁
  • 执行引擎 —— CPU执行操作

JMM图

JMM存在的必要性

工作内存和主内存数据如何交互?

JMM定义了以下数据同步八大原子操作来实现

八大原子操作

指令行为位置
read主内存拷贝一份变量的数据副本主内存
load数据副本加载到工作内存主内存->工作内存
use执行引擎使用给数据副本工作内存->执行引擎
assign执行引擎赋值给数据副本执行引擎->工作内存
store数据副本传回主内存工作内存->主内存
write数据副本赋值给原变量主内存
lock主内存变量标记为线程独占主内存
unlock主内存变量取消线程独占主内存

数据交互顺序:

  • 主内存变量 read 生成数据副本
  • 数据副本 load 进工作内存
  • 执行引擎 use 数据副本
  • 执行引擎 assign 给数据副本
  • 数据副本 store 到主内存
  • 主内存数据副本 write 给原变量

数据交互中可能产生的问题

因为工作内存是线程私有的,而主内存的资源是共享的,在多线程并发的情况下,就有可能导致脏写更新覆盖】的问题

怎么解决?

首先需要了解,并发编程的三大特性

并发编程的三大特性

原子性

​ 原子性是指:**一个操作不可中断,**即使在多线程情况下,一个操作一旦开始就不会被其他线程影响。

​ Java规定**对于基本数据类型的读写操作是原子的**

可见性

​ 可见性是指:一个线程修改了某个共享变量的值,其他线程能够马上得知这个修改的值

​ 在多线程情况下,线程A修改了共享变量X的值,而还未写回主内存时,此时线程B读到共享变量X的值【仍为旧值】,这种 工作内存与主内存同步延迟现象 造成了可见性问题。

有序性

​ 因为指令重排序【性能优化】,导致在多线程情况下有可能导致指令顺序未必一致的问题

四个问题

怎么解决原子性问题?

可以通过加锁的方式来实现原子性

  • synchronized
  • Lock

加锁可以保证 任一时刻只有一个线程访问该代码

怎么解决可见性问题?

  1. volatile 关键字保证可见性

    他能保证共享变量x的值被修改后能立即被其他线程看到

  2. 加锁可以保证可见性

    因为加锁可以保证 任一时刻只有一个线程访问该代码,释放锁之前,共享变量的值被刷新回主内存

怎么解决有序性问题?

  1. volatile 关键字保证有序性

    禁止指令重排序,从而保证有序性

  2. 加锁可以保证可见性

    因为加锁可以保证 任一时刻只有一个线程访问该代码,相当于单线程环境下,自然有序

什么是指令重排序?

只要程序的最终结果与JVM顺序化情况的结果相等,那么指令的执行顺序 可以 与代码顺序不一致,此过程叫指令重排序 【为了符合CPU特性,增强性能】

指令重排序遵循as-if-serial语义happens-before原则

as-if-serial语义

不管怎么重排序,程序执行结果都不能被改变。

happens-before 原则

规则解释
程序顺序原则在一个线程内必须保证语义顺序执行 【可重排】
锁规则如果对于一个锁解锁后,再加锁,那么加锁的动作必须在解锁动作之后
volatile规则volatile变量的写,先发生于读【读最新值】
线程启动规则如果线程A在执行线程B的start()之前修改了共享变量的值,那么当线程B执行start()时,线程A对共享变量的修改对线程B可见
传递性A先于B ,B先于C 那么A必然先于C
线程终止规则线程的所有操作先于线程的终结
线程中断规则先调用线程interrupt(),再检测中断事件的发生interrupted()
对象终结规则对象的构造函数执行,结束先于finalize()方法 【GC】

http://www.ngui.cc/el/4893709.html

相关文章

MESI与Volatile(二)

MESI缓存一致性协议 定义: 多核CPU的情况下有多个一级缓存,一致性协议MESI保证缓存内部数据的一致,不让系统数据混乱。 缓存行(Cache line):缓存存储数据的单元 缓存行状态: 状态描述监听任务M 修改 (Mo…

synchronized锁机制(三)

Java锁机制(一) 定义: ​ 锁的设计是为了解决线程并发安全问题,Java提供了两种锁来实现同步互斥访问 synchronized 和 lock Monitor监视器锁 定义: ​ 任何一个对象都有一个Monitor与之关联,通过成对的…

AQS框架详解(四)

AQS概述 定义 AbstractQueuedSynchronizer 抽象队列同步器是一个框架,它维护两种队列,基于一个状态量 state 来实现同步器,实现该框架时,仅仅需要实现几种方法就可以自定义同步器 两种队列 同步等待队列 CLH CLH队列是一种基于…

AQS框架应用(五)

AQS框架应用(五) 定义: ​ 基于AQS框架,Doug Lea给出了很多内置的实现类 实现类: 可以看出,有多个工具类是基于AQS框架实现的 独占式同步信号量 ReentrantLock Semaphore 共享式同步信号量 CountDown…

类加载机制(一)

类加载 定义: ​ 当 用到某个类 时,首先需要通过 类加载器 把类加载到JVM上 组成: 引导类加载器 —— 加载lib目录扩展类加载器 —— 加载ext目录应用程序类加载器 —— 加载ClassPath目录 【用户写的】自定义加载器 —— 加载用户自定义…

JVM内存模型(二)

JVM内存模型 定义: ​ JVM内存模型,又称为运行时数据区。【区别Java内存模型】 紫色 —— 线程私有 浅黄色 —— 线程共享 虚拟机栈 定义: ​ 虚拟机栈是一个线程私有的、FILO的结构。 ​ 一个线程到来时,从虚拟机栈中&…

JVM内存分配机制详解(三)

JVM对象创建过程 1.类加载检查 流程: JVM在遇到一条new指令检查这个指令的参数是否在常量池中定位到一个类的符号引用 【方法区】并检查 符号引用 所代表的类是否被类加载器加载 包括 new关键字、对象克隆、对象序列化等等 **总的来说:**执行一个类…

Spring IOC (三)

Spring IOC (三) refresh() 后八个方法 refresh() 定义: ​ 这个方法中,内置了13个方法,做了很多事情 方法: 方法作用prepareRefresh()保存了容器的启动时间,启动标志等obtainFreshBeanFac…

Spring循环依赖(四)

循环依赖 什么是循环依赖? 依赖:在Spring中,A类将其他的类当作属性时,就造成了A依赖其他类 定义: ​ 现有A、B两个类,如果A类将B类作为属性(并设置Autowired),B类也将…

想要学习Python?8年老Python程序员的自学书单曝光,入门必看

什么是Python? 它是一种类似C语言的人工智能便捷语言。它简单易学、并且开源免费,应用面广,所以,是自学门槛相对低的一种计算机语言,能为你的生活、工作提升效率。 为什么选择学习python的人越来越多? 全…