Java内存模型了解一下

JMM

      • 1、什么是JMM?
      • 2、Java内存模型(图解)
      • 3、JMM执行读/写操作的规范
      • 4、Happens-Before原则
        • 4.1 定义
        • 4.2 相关规则

1、什么是JMM?

Java内存模型(简称JMM,Java Memory Model)是一种抽象的概念,它描述的是 一组规范 ,通过这组规范定义了程序中各个变量(包括:实例变量,静态字段,构成数组对象的元素)的访问方式,以实现让Java程序在各种平台下都能达到 一致的内存访问效果 ,从而屏蔽各种硬件和操作系统的内存访问差异。

JMM也是理解线程之间安全高并发的基础。

注意:
Java内存模型和Java虚拟机内存区域是不同的两个概念,前者跟线程访问内存有关,而后者才是所谓的执行引擎、类加载器、JVM运行时数据区域(堆、方法区、JVM栈、本地方法栈、程序计数器)。

2、Java内存模型(图解)

Java内存模型了解一下_第1张图片
Java内存模型定义了8种操作,来实现工作内存和主存之间的交互。其中在主存内工作的有lock、unlock、read、write;在工作内存中操作的有load、use、assign、store。

  • lock & unlock:都作用于主存,lock把一个变量标志为一条线程独占的状态,unlock用于释放锁定的变量。这里要说明一点,volatile只能实现变量之间的可见性,并不能实现原子性,若要实现原子性操作,还需进行加锁
  • read:把一个变量从主存传输到线程的工作内存中。
  • load:把read操作传入的变量值赋值给工作内存的变量副本中。
  • use:把工作内存中的变量传递给执行引擎。用于执行变量的操作。
  • assign:将执行引擎处理好了的值赋值回工作内存中的变量。
  • store:把工作内存中的变量传递给主存中的变量。
  • write:把从store中得到的变量写入主存的变量中。

3、JMM执行读/写操作的规范

Java内存模型还规定了在执行上述8种基本操作时必须满足的规则:

(1)不允许read和load、store和write操作之一单独出现,也既读了主存就一定转载到工作内存,存储到内存后就一定会写入变量。

(2)不允许一个线程丢弃它最近的assign操作既变量在工作内存中改变了之后,必须 同步回主内存

(3)没有发生任何assign操作之前,不允许将数据同步回主内存

(4)一个新变量只能在主存中产生,不允许直接在工作内存中使用一个未被初始化的变量。

(5)一个变量在同一时刻只允许一条线程对其进行lock操作。

(6)如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作以初始化变量的值

(7)对一个变量执行unlock操作之前,必须先把此变量同步回主内存中。

这8种内存访问操作以及以上规定,加上volatile的特例,就已经能准确地描述出Java程序中哪些内存访问操作在并发下才是安全的。

4、Happens-Before原则

与以上操作规范等效的且稍微简单的判断原则——先行发生原则(Happens-Before)。该原则用于 判断数据是否存在竞争,线程是否安全 。依赖这个原则,我们可以通过几条简单规则一揽子解决并发环境下两个操作之间是否可能存在冲突的所有问题,而不需要陷入Java内存模型苦涩难懂的定义之中。

4.1 定义

  • 操作A
  • 操作B

操作A先行发生于操作B,A操作所产生的“影响”,包括改变内存中共享变量的值,发送了消息,调用了方法等,被操作B观察到。

4.2 相关规则

  • 程序次序规则一个线程内,按照控制流顺序,书写在前的操作先行发生于书写在后的。
  • 管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作。
  • volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作。
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作。
  • 线程终止规则:线程中所有的操作都先行发生于对此线程的终止操作。
  • 线程中断规则:对线程interrupt()方法调用先行发生于检测到中断的事件的发生。
  • 对象终结规则:一个对象的初始化先行发生于它的finalize()方法的开始。
  • 传递性:A先行发生于B,B先行发生于C,则A先行发生于C。

你可能感兴趣的:(多线程,JVM)