一、什么是 JMM
JMM : Java 内存模型,它并不实际存在,是一种概念,一种约定!
作用 :主要是定义了 线程 与 主内存 之间存取数据的一些规则,进行一定的约束。
二、关于 JMM 的约定
- 线程加锁前,必须读取最新的数据的到工作内存中去!
- 线程解锁前,必须立刻把修改后的数据,刷新到主存!
- 加锁,解锁,都是同一把锁。
三、主存和线程的交互
关于主内存和线程的工作内存之间的交互,Java内存模型定义了8种原子操作:
- lock,之后来的线程,就只能读取。
- read,读取到工作内存中
- load,赋给变量副本
- use,执行引擎需要使用的时候,传递给它
- assign,如果中途修改了,则进行更新
- store,使用完了,存储到主存中去
- write,写回到主存的变量
- unlock,解锁了!
如图:
Java内存模型还规定了执行上述8种基本操作时必须满足如下规则:
(1)不允许read和load、store和write操作之一单独出现(即不允许一个变量从主存读取了但是工作内存不接受,或者从工作内存发起会写了但是主存不接受的情况),以上两个操作必须按顺序执行,但没有保证必须连续执行,也就是说,read与load之间、store与write之间是可插入其他指令的。
(2)不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。
(3)不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中。
(4)一个新的变量只能从主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
(5)一个变量在同一个时刻只允许一条线程对其执行lock操作,但lock操作可以被同一个条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。
(6)如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
(7)如果一个变量实现没有被lock操作锁定,则不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量。
(8)对一个变量执行unlock操作之前,必须先把此变量同步回主内存(执行store和write操作)
存在的问题:
因为约定了,每个线程必须读取的是最新的值,那么就有一个可见性问题了!
不过Java也提供了解决方案: volatile 则用于解决这个问题!