0%

JMM

JMM

JMM(Java Memony Mode)java内存模型,JMM描述了java线程如何通过内存进行交互,java程序中各种变量(线程共享变量)的访问规则,以及在jvm中将变量存储到内存和从内存中读取出变量的底层细节

  • 所有变量都存储在主内存
  • 每个线程都有自己独立的工作内存,里面保存该线程使用到的变量的主内存副本拷贝,线程读写变量时操作的是自己工作内存中的变量(线程操作共享变量时,先从主内存复制共享变量到自己的工作内存,然后对工作内存里的变量进行处理,处理完之后将变量值更新到主内存)

有两条规定

  • 线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写
  • 不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成

volatile修饰的变量依然有共享内存的拷贝,但是在从工作内存中读写数据前,必须先将主内存中的数据同步到工作内存中,所以看起来如同直接在主内存中读写访问一般

happens-before规则

  • 程序次序规则:同一个线程的每个动作都happens-before于出现在其后的任何一个动作
  • 锁定规则:对一个监视器的解锁happens-before于每一个后续对同一个监视器的加锁
  • volatile变量规则:对volatile字段的写入操作happens-before于每一个后续的同一个字段的读操作
  • 线程启动规则:Thread.start的调用会happens-before于启动线程里的其他操作
  • 线程终止规则:Thread中的所有动作都happens-before于其他线程检查到此线程结束
  • 线程中断规则:一个线程A调用另一个线程B的interrupt()都happens-before于线程A发现B被A中断
  • 对象终结规则:一个对象构造函数结束happens-before于该对象的finalize方法的开始
  • 传递规则:如果动作A happens-before于动作B,而动作B happens-before于动作C,则动作A happens-before 于动作C

内存间交互操作

交互操作

java内存模型中定义了以下8种操作来完成主内存与工作内存之间交互的实现细节

  • luck(锁定) 作用于主内存的变量,把一个变量标识为锁定的状态
  • unlock(解锁) 作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才能被其他线程锁定
  • read(读取) 作用于主内存的变量,把一个变量的值从主内存传输到工作内存,以便之后的load动作使用
  • load(载入) 作用于工作内存的变量,把read操作从主内存中得到的变量值放入到工作内存的变量副本中
  • use(使用) 作用于工作内存的变量,把工作内存中的一个变量传递给执行引擎,当虚拟机遇到一个需要使用变量的值的字节码指令时会执行该操作
  • assign(赋值) 作用于工作内存的变量,把一个从执行引擎接收到的值赋给工作内存的变量,当虚拟机遇到一个变量赋值的字节码指令时执行该操作
  • store(存储) 作用于工作内存的变量,把工作内存中的一个变量的值传递到主内存中,以便之后的write操作使用
  • write(写入) 作用于主内存的变量,把store操作从工作内存中得到的值放入到主内存变量中

交互规则

  • 不允许read和load、store和write操作单独出现,以上两个操作必须按照顺序执行,但是指令之间可插入其他指令
  • 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步到主内存
  • 不允许一个线程没有发生过任何assign操作把数据从线程的工作内存同步到主内存中
  • 一个新的变量只能从主内存中创建,不允许在工作内存中直接使用一个未被初始化的变量,即对一个变量进行use或store操作之前,必须先执行assign和load操作
  • 一个变量在同一时刻只允许一条线成对其进行lock操作,但lock操作可以被同一线程重复多次,多次执行lock后,需要执行相同次数的unlock操作,才会被解锁
  • 如果对一个变量执行lock操作,将清空工作内存中此变量的值,在执行引擎使用该变量时,需要重新执行load或assign操作初始化变量的值
  • 如果一个变量实现没有被lock操作锁定,则不允许对它执行unlock操作,也不允许unlock一个被其他线程锁定的变量
  • 对一个变量执行unlock之前,必须先把变量同步到主内存(执行store和write操作)