加 – 并发编程基础




并发的一些基础概念

CPU 多级缓存

为了解决CPU与主存间速度不匹配的问题.

时间局部性

数据可能被重复访问

空间局部性

数据周围的一些数据,也可能被访问

缓存一致性(MESI协议)

为了搞定共享数据一致的问题

M: 已修改,待写回
E: 缓存只被缓存在CPU中,未被修改,修改后转为 M
S: 共享态,可能被多个CPU共享
I: 有其他CPU修改了缓存行

lr: 本地读
lw: 本地写
rr: 内存读
rw: 缓存写到主存

状态转换

乱序执行优化

这点与之前JVM对中间代码的优化一致,可能会导致在优化过程中导致的代码乱序执行(如果是并行则对原结果不影响),乱序优化是CPU为了提高执行效率(因为各组件的数量是有限的,为了防止一直等待一个组件而导致的时间浪费进行优化).

脏数据

Java内存模型(JMM)

之前也聊过.
JMM: Java Memory Model

(为了屏蔽掉各种硬件和操作系统的访问差异,使一个代码在各平台下都可正常并行)

JMM是一个规范模型.
规定一个线程如何和何时可以看到由其他变量修改过后的共享变量的值.以及在必须时如何同步的访问共享变量.

堆是在运行时动态分配,存取速度慢.
栈,存取速度快,存储空间一定.
线程在栈上.
对象在堆上,引用在栈上.

高速缓存

CPU与主存间的缓存.

抽象


线程间通讯,必须通过主内存.
故出现问题就是因为主内存中没处理代码同时执行的操作.

同步的八种操作以及操作规则

(1)lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态
(2)unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
(3)read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
(4)load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
(5)use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎
(6)assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
(7)store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作
(8)write(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中
如果要把一个变量从主内存中复制到工作内存中,就需要按顺序地执行read和load操作,如果把变量从工作内存中同步到主内存中,就需要按顺序地执行store和write操作。但Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。

同步规则分析:
1)不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步会主内存中
2)一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或者assign)的变量。即就是对一个变量实施use和store操作之前,必须先自行assign和load操作。
3)一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现。
4)如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量之前需要重新执行load或assign操作初始化变量的值。
5)如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
6)对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)