目录
硬件内存模型
目前的CPU为了提高性能,CPU不会直接会内存交互而是先与缓存交互,仅当读取不到才与内存进行交互;
特点:越靠近cpu速度越快,L1>L2>L3>内存;
那么就会存在一个问题,在并发情况下,CPU读取的值可能不一样,缓存一致性问题怎么解决?
① 锁总线:通过给总线加锁,当某个操作操作该某一共享变量时,其他CPU禁止访问内存;
缺点:锁的颗粒太大了,影响性能,降低CPU的吞吐量。
② 缓存一致性协议(MESI):当CPU写数据时,如果发现操作的变量是共享变量,通过总线出发总线的嗅探机制,
会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,
发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。
Java线程与硬件处理器关系
java内存模型
java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,是一个抽象模型概念,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。
工作空间与主内存之间的交互
java内存中线程的工作内存和主内存的交互是由java虚拟机定义了如下的8种操作来完成的,每种操作必须是原子性的。
① lock(锁定):作用于主内存的变量,一个变量在同一时间只能一个线程锁定,该操作表示这条线成独占这个变量;
② unlock(解锁):作用于主内存的变量,表示这个变量的状态由处于锁定状态被释放,这样其他线程才能对该变量进行锁定;
③ read(读取):作用于主内存变量,表示把一个主内存变量的值传输到线程的工作内存,以便随后的load操作使用;
④ load(载入):作用于线程的工作内存的变量,表示把read操作从主内存中读取的变量的值放到工作内存的变量副本中
(副本是相对于主内存的变量而言的);
⑤ use(使用):作用于线程的工作内存中的变量,表示把工作内存中的一个变量的值传递给执行引擎,每当虚拟机遇到一个
需要使用变量的值的字节码指令时就会执行该操作;
⑥ assign(赋值):作用于线程的工作内存的变量,表示把执行引擎返回的结果赋值给工作内存中的变量,每当虚拟机遇到
一个给变量赋值的字节码指令时就会执行该操作;
⑦ store(存储):作用于线程的工作内存中的变量,把工作内存中的一个变量的值传递给主内存,以便随后的write操作使用;
⑧ write(写入):作用于主内存的变量,把store操作从工作内存中得到的变量的值放入主内存的变量中。
并发编程三个特性
原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行;
可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值;
有序性:即程序执行的顺序按照代码的先后顺序执行;
编译器和处理器为了执行效率可能会编译器重排序、指令重排序。
并发编程的特性保证
① JMM与原子性:
Synchronized
JUC Lock的lock
② JMM与可见性:
volatile:在JMM模型上实现MESI协议
synchronized:加锁
③ JMM与有序性:
as-if-serial语义:在不存在依赖关系的情况下允许编译器和处理器的指令重排序(单线程);
happens-before原则:
程序顺序原则:前一个操作对后一个操作可见,且前一个操作排在后一个前面,如果前一个操作不需对后一个可见,那么JMM
允许进行重排序;
锁原则:后一次加锁必须等前一次的释放锁;
volatile原则:编译器在生成字节码时,通过在指令序列中插入内存屏障禁止重排序,从而保证有效性;
传递原则:A--->B B-->C 推导出 C--->A
JMM基于保守策略插入内存屏障规则如下:
1.在每个volatile写操作的前面插入一个StoreStore屏障。
2.在每个volatile写操作的后面插入一个StoreLoad屏障。
3.在每个volatile读操作的前面插入一个LoadLoad屏障。
4.在每个volatile读操作的后面插入一个LoadStore屏障。