菜鸟笔记
提升您的技术认知

java内存模型JMM

java内存模型

jmm(java memory model)规范,他规范了java虚拟机与计算机内存如何协调工作 ,他规定了一个线程如何及何时看到其他线程修改过的变量的值,以及在必须时,如何同步的访问共享变量。

jmm内存分配的概念:

堆heap: 优点:运行时数据区,动态分配内存大小,有gc;,缺点:因为要在运行时动态分配,所以存取速度慢,对象存储在堆上,静态类型的变量跟着类的定义一起存储在堆上。
栈stack:存取速度快,仅次于寄存器,缺点:数据大小与生存期必须是确定的,缺乏灵活性,栈中主要存放基本类型变量(比如,int,shot,byte,char,double,foalt,boolean和对象句柄),jmm要求,调用栈和本地变量存放在线程栈上

当一个线程可以访问一个对象时,也可以访问对象的成员变量,如果有两个线程访问对象的成员变量,则每个线程都有对象的成员变量的私有拷贝,

计算机 硬件架构:

处理器(cpu): 寄存器:每个cpu都包含一系列寄存器,他们是cpu的基础,寄存器执行的速度,远大于在主存上执行的速度
cpu高速缓存:由于处理器与内存访问速度差距非常大,所以添加了读写速度尽可能接近处理器的高速缓存,来作为内存与处理器之间的缓冲,将数据读到缓存中,让运算快速进行,当运算结束,再从缓存同步到主存中,就无须等待缓慢的内存读写了。处理器访问缓存的速度快与访问主存的速度,但比访问内部寄存器的速度还是要慢点,每个cpu有一个cpu的缓存层,一个cpu含有多层缓存,,某一时刻,一个或者多个缓存行可能同时被读取到缓存取,也可能同时被刷新到主存中,同一时刻,可能存在多个操作,
内存:一个计算机包含一个主存,所有cpu都可以访问主存,主存通常远大于cpu中的缓存,
运作原理: 通常,当一个cpu需要读取主存时,他会将主存的内容读取到缓存中,将缓存中的内容读取到内部寄存器中,在寄存器中执行操作,当cpu需要将结果回写到主存中时,他会将内部寄存器的值刷新到缓存中,然后会在某个时间点将值刷新回主存

jmm 和硬件内存架构:

硬件没有区分线程栈和堆,线程栈和堆主要在分布在主内存中,有时部分线程栈和堆会分布在cpu寄存器和cpu缓存中

jmm抽象结构

线程中共享变量都存储在主内存中,每个线程都有个私有的本地工作内存,私有本地工作内存是jmm模型抽象概念,并不是真实存在的,她涵盖了缓存,协缓存区,寄存器以及其他的硬件和编译器的优化,本地内存中存储了该线程以读或写共享变量的拷贝的副本,比如线程1 要使用主内存中的变量a,线程1回先拷贝出变量a 的副本存储在自己的本地内存。从更低的层次来说,主内存就是硬件的内存,是为了获取更好的运行速度,虚拟机及硬件系统会让工作内存优先存储于寄存器和高速缓存中,jmm中线程中的工作内存是硬件系统中cpu的寄存器和高速缓存的一个抽象描述,jvm模型是对内存的物理划分,只局限在内存,只局限在jvm内存。如果线程之间的通信必须经过主内存,例如:线程a要将本地工作内存中的变量刷新到主内存中的共享变量,线程b去主内存中读取刚刚被线程a更新后的共享变量。

java内存模型 - 同步操作与规则

Java内存模型-同步八种操作

  1. lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态
  2. unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来 , 释放后的变量才可以被其他线程锁定unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来 , 释放后的变量才可以被其他线程锁定
  3. read(读取) : 作用于主内存的变量 , 把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用read(读取) : 作用于主内存的变量 , 把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
  4. load(载入):作用域工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中load(载入):作用域工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
  5. use (使用) : 作用于工作内存的变量 , 把工作内存中的一个变量值传递给执行引擎use (使用) : 作用于工作内存的变量 , 把工作内存中的一个变量值传递给执行引擎
  6. assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量
  7. store (存储) : 作用于工作内存的变量 , 把工作内存中的一个变量的值传送到主内存中 , 以便随后的write的操作
  8. write (写入) : 作用于主内存的变量, 它把store操作从工作内存中一个变量的值传送到主内存的变量中

Java内存模型-同步规则

  1. 如果要把一个变量从主内存中复制到工作内存, 就需要按顺序地执 行read和load操作 , 如果把变量从工作内存中同步回主内存中, 就要按顺序地执行store和write操作. 但Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行
  2. 不允许read和load、 store和write操作之一单独出现
  3. 不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中
  4. 不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中
  5. 一个新的变量只能在主内存中诞生, 不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。 即就是对一个变量实施use和store操作之前 , 必须先执行过了assign和load操作
  6. 一个变量在同一时刻只允许一条线程对 其进行lock操作 , 但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现
  7. 如果对一个变量执行lock操作,将会清空工作内存中此变量的值, 在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
  8. 如果一个变量事先没有被lock操作锁定 , 则不允许 对它执行unlock操作 ; 也不允许去unlock一个被其他线程锁定的变量
  9. 对一个变量执行unlock操作之前 , 必须先把此变量同步到主内存中(执行store和write操作)