java并发编程与高并发-2并发基础
CPU多级缓存
CPU多级缓存-- 缓存一致性 (MESI)
Cache一致性协议在MESI协议中,每个Cacheline有4个状态,可用两个bit表示,它们分别是
状态 |
描述 |
M(Modified) |
这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本cache中 |
E(Exclusive) |
这行数据有效,数据和内存中的数据一致,数据只存在于本cache中。 |
S(Shared) |
这行数据有效,数据和内存中的数据一致,数据存在于很多cache中 |
I(Invalid) |
这行数据无效 |
____________________________________________________________________________
CPU多级缓存 -- 乱序执行优化
概念:
在单核时代, 处理器保证做出的优化不会导致运行结果远离预期目标.
但在多核时代并非如此 !
如果我们不做任何措施, 结果会与我们得到的结果大不相同 .
___________________________________________________________________________
Java内存模型(JMM)
java虚拟机定义了java内存模型.
JMM是一种规范.
-
规定了java虚拟机和内存是如何协同工作的.
-
规定了一个线程如何和何时可以看到其他线程修改过的共享变量的值. 以及在必须时如何同步的访问共享变量。
-
堆: 运行时动态分配内存 ,所以存取相对的慢。存放对象。
-
栈: 存取速度比堆要快,仅次于寄存器。 数据可以共享。存放基本类型的变量。存放引用。
如果两个 线程同时调用了同一个对象(Object3)上的同一个方法,
他们都会访问这个对象的成员变量。但是每个对象都会有这个变量的私有拷贝**
计算机架构图示:
这里是多CPU。
每个cpu都包含寄存器。访问的速度远大于访问主存的速度。
高级缓存:内存与处理器之间的缓冲。把运算要的数据复制到缓存,使运算能快速进行。计算完成后,再从缓存同步回内存。处理器就无需等待缓慢的内存读写了。 cpu访问缓存的速度快于访问主存的速度,但慢于访问内部寄存器的速度
主存:所有cpu都可以访问主存,比cpu的缓存大得多
内存模型和计算机架构之间的关系
线程和主内存的抽象关系:
本地内存*:是java内存模型里一个抽象的概念,并不是真实存在的。它涵盖了 缓存,写缓冲区,寄存器以及其他硬件的一些优化。
其中存储了共享变量的副本。从更低的层次来说主内存就是硬件的内存,是为了获取更好的运行速度虚拟机以及硬件系统让工作内存优先存储于 寄存器和高速缓存中。 java内存模型中的工作内存是寄存器和高速缓存的抽象描述,
JVM内存模型只是对内存的一种物理划分而已,只局限在内存。
从这张图你们就可以看出为什么之前的count到不了5000了。
所以我们得加一些同步手段来增加并发时程序的准确性
____________________________________________________________________________
Java内存模型 -- 同步八种操作
-
lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态
-
unlock (锁定):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
-
read (读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
-
load (载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
-
use (使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎
-
assign (赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量
-
store (存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作
-
write (写入):作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中
Java内存模型还规定了在执行上述八种基本操作时,必须满足如下规则:
-
不允许read和load、store和write操作之一单独出现
-
不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中。
-
不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中。
-
一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
-
一个变量在同一时刻只允许一条线程对其进行lock操作,lock和unlock必须成对出现
-
如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
-
如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
-
对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)。
____________________________________________________________________________