并发基础:Java内存模型

一.现代计算机的并发问题

1.现代的多CPU计算机已经普及,也就意味着有多Cache,并发时也就意味着存在着一定的风险:

现在我们要让计算机计算1+1-1的操作,计算机进行多核并发运算:
假如两个CPU同时从主存中读到同一个数据1存到各自的缓存中,CPU1将其加1结果2存到主存中,另一个CPU2将其减一结果0存到主存中,如果是CPU1的存入执行先于2,那么最后结果为0,反之结果为2,它们都不是正确的结果,我们要的正确结果为1
在这里插入图片描述
2.对于CPU多缓存的并发数据安全问题,诞生了MESI协议,该协议用于保证多个CPU 缓存之间共享数据的一致性。

二.Java内存模型(JMM)

1.JMM规范了计算机内存与JVM如何协同工作的,它规定了一个线程如何和何时可以看到其他线程修改后的共享变量,以及如何同步的访问共享变量。

2.它主要分为:
Heap区:主要对应于计算机的主存,存取速度慢,主要存放对象,静态成员变量。
Stack区:主要对应于计算机的缓存和cpu寄存器,存取速度快,存放基本类型变量,本地变量。

在这里插入图片描述
3.JMM规范:
1)八种同步操作:
lock, read, load ,use assign, store, write ,unlock
在这里插入图片描述
2)八种操作的同步规则:
—如果要把一个变量从主存中复制到工作内存中,就需要按顺序地执行read和load操作,反之,如果要把变量从工作内存中同步回主存中就要按顺序的执行store和write操作。(JMM只要求按顺序执行,没有规定必须连续,它们之间允许存在其他操作)

—read和load,store和write必须成对出现

—不允许一个线程丢弃它最近的assign操作,换句话说就是变量如果在工作内存中改变后必须同步到主存中

—不允许一个线程没有原因的把数据从工作内存同步回主存中

—新的变量只能在主存中产生,不允许工作内存中直接使用一个未load的变量

—一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被一条线程重复执行多次,且lock和unlock必须成对

—对一个主存中变量执行lock操作,JMM将会清空工作内存中此变量的此前的值,在执行引擎使用这个变量前需要重新执行load操作初始化变量的值

—如果一个变量事先没有被lock锁定,则不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量

—对一个变量进行unlock操作执行,必须先把此变量同步到主存中

JMM从相对于底层的层面保证了数据安全。