并发基础:Java内存模型
本文目录
一.现代计算机的并发问题描述
1.什么是并发?
简单来说,并发就是多个线程“同时”运行。 假设一个程序中有多个线程,如果程序在单核处理器上运行,那么多个线程将交替地换入或者换出内存,每个线程都处于执行过程中地某个状态。如果运行在多核处理器上,此时,程序中的每个线程都将分配到一个处理器核中,因此可以同时运行。
2.什么是高并发?
高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常指通过设计保证系统能够 同时并行处理多个请求 。
3.并发存在的风险
现代的多CPU计算机已经普及,也就意味着有多Cache,并发时也就意味着存在着一定的风险:
现在我们要让计算机计算1+1-1的操作,计算机进行多核并发运算:
上面的计算可能会被分解成两个任务:对原始内存中1的加一操作和减一操作,如果这两个任务没有定义执行顺序,那么可能会发生下面的事情:
两个CPU同时从主存中读到同一个数据1存到各自的缓存中,然后各自对对它进行操作,CPU1将其加1结果2存到主存中,另一个CPU2将其减一结果0存到主存中,那么结果就可能变为 :如果是CPU1的存入执行先于2,那么最后结果为0,反之结果为2,它们都不是正确的结果,我们要的正确结果为1
这就是并发所带来的风险:影响结果的正确性,而结果的正确性在生产环境中是极为重要的!!!

对于CPU多缓存的并发数据安全问题,诞生了MESI协议,该协议用于保证多个CPU 缓存之间共享数据的一致性。
二.Java内存模型(JMM)
1.什么是JMM?
JMM规范了计算机内存与JVM如何协同工作的,它规定了一个线程如何和何时可以看到其他线程修改后的共享变量,以及如何同步的访问共享变量。
2.JMM主要分区
Heap区:主要对应于计算机的主存,存取速度慢,主要存放对象,静态成员变量。
Stack区:主要对应于计算机的缓存和cpu寄存器,存取速度快,存放基本类型变量,本地变量。

3.JMM规范
1)八种同步操作
lock, read, load ,use assign, store, write ,unlock

2)八种操作的同步规则
1.如果要把一个变量从主存中复制到工作内存中,就需要按顺序地执行read和load操作,反之,如果要把变量从工作内存中同步回主存中就要按顺序的执行store和write操作。(JMM只要求按顺序执行,没有规定必须连续,它们之间允许存在其他操作)
2.read和load,store和write必须成对出现
3.不允许一个线程丢弃它最近的assign操作,换句话说就是变量如果在工作内存中改变后必须同步到主存中
4.不允许一个线程没有原因的把数据从工作内存同步回主存中
5.新的变量只能在主存中产生,不允许工作内存中直接使用一个未load的变量
6.一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被一条线程重复执行多次,且lock和unlock必须成对
7.对一个主存中变量执行lock操作,JMM将会清空工作内存中此变量的此前的值,在执行引擎使用这个变量前需要重新执行load操作初始化变量的值
8.如果一个变量事先没有被lock锁定,则不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量
9.对一个变量进行unlock操作执行,必须先把此变量同步到主存中
JMM从相对于底层的层面保证了数据安全。
三.CPU多级缓存
1.为什么需要CPU cache?
因为CPU的频率太快了,快到主存跟不上,这样在处理器时钟周期内,CPU常常需要等待主存,浪费资源。 所以cache的出现,是为了缓解CPU和内存之间速度不匹配的问题。(注意:是缓解,并不是解决了)
2.带有高速缓存的CPU执行计算的流程如下
1)程序以及数据被加载到主存
2)指令和数据被加载到CPU的高速缓存
3)CPU从高速缓存中得到数据执行指令,并把结果写到高速缓存中
4)高速缓存中的数据被写回主内存
3.CPU cache的意义
局部性原理:
1)时间局部性:如果某个数据被访问,那么在不久的将来,它很可能被再次访问。
2)空间局部性:如果某个数据被访问,那么与它相邻的数据很快也可能被访问。
4.CPU多级缓存的缓存一致性协议(MESI)
它用于保证多个Cpu cache之间缓存共享数据的一致。
目前流行的多级缓存结构如下:

我们很容易知道,多个CPU的情况下会有多个一级缓存,那么如何保证缓存内部数据的一致而不让系统数据混乱, MESI就是解决这个问题的。
1)MESI的含义: 它分别是由这个协议中描述缓存行的四个状态的首字母组成
| 状态 | 描述 |
|---|---|
| Modified(修改) | 该缓存行有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中 |
| Exclusive(独享) | 该缓存行有效,数据和内存中的数据一致,数据只存在于本Cache中 |
| Shared(共享) | 该缓存行有效,数据和内存中的数据一致 ,数据被多个Cache共享 |
| Invalid(无效) | 该缓存行无效 |
2)MESI状态转换

触发事件:
| 触发事件 | 描述 |
|---|---|
| Local read | 本地cache读取本地cache数据 |
| Local write | 本地cache写入本地cache数据 |
| Remote read | 其他cache读取本地cache数据 |
| Remote write | 其他cache写入本地cache数据 |
下图示意了当一个缓存行调整状态的时候,另外一个缓存行需要调整的状态:

5.乱序执行优化
1)什么是乱序执行优化?
处理器为了提高计算速度而做出违背代码原有顺序的优化。
单核时代处理器的乱序执行优化不会使预期的目标偏离,但是在多核时代并不会这样,如果我们不做一些防护措施,最后得出的结果会和我们预期的结果大不相同。
四.并发的优势和风险
1.优势
1)速度:并发程序可以同时处理多个请求,响应速度更快,且一些复杂的操作可以分成多个进程同时进行。
2)设计:运用并发技术我们在设计程序的时候在某些请况下变得更简单,也可以有更多的选择。
3)资源利用:并发程序可以极大的提高资源利用率。(例如CPU能够在等待IO的时候做一些其他计算)
2.风险
1)安全性问题:当多个线程共享数据时可能会发生期望偏离的结果。
2)活跃性问题:活跃性问题指的是线程中某些操作无法执行下去了,比如:发生死锁。
3)性能问题:线程过多时会使CPU频繁切换,调度时间增加,降低性能,以及消耗过多内存资源。

浙公网安备 33010602011771号