冯诺依曼计算机模型
- 控制器(Control)
- 运算器(Datapath)
- 存储器(Memory)
- 输入(Input system)
. 输出(Output system)
- CPU内部结构
CPU的结构主要由运算器、控制器、寄存器三大块组成。
运算器就是中央机构里负责执行任务的部门,也就是专门干活的;而控制器就是中央机构的领导小组,针对不同需要,给运算器下达不同的命令;寄存器可以理解为控制器和运算器之间的联络小组,主要工作就是协调控制器和运算器。
多核CPU多级缓存一致性协议MESI
多核CPU的情况下有多个一级缓存,如何保证缓存内部数据的一致,不让系统数据混乱。这里就引出了一个一致性的协议MESI。
MESI协议缓存状态
MESI 是指4中状态的首字母。每个Cache line有4个状态,可用2个bit表示,它们分别是:
缓存行(Cache line):缓存存储数据的单元。
状态 | 描述 | 监听任务 |
---|---|---|
M 修改 (Modified) | 该Cache line有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。 | 缓存行必须时刻监听所有试图读该缓存行相对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成S(共享)状态之前被延迟执行。 |
E 独享、互斥 (Exclusive) | 该Cache line有效,数据和内存中的数据一致,数据只存在于本Cache中。 | 缓存行也必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成S(共享)状态。 |
S 共享 (Shared) | 该Cache line有效,数据和内存中的数据一致,数据存在于很多Cache中。 | 缓存行也必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该缓存行变成无效(Invalid)。 |
I 无效 (Invalid) | 该Cache line无效。 | 无 |
- 缓存行失效
- 存储的长度过大(总线加锁)
- cpu 不支持缓存一致性协议
线程
进程是系统分配资源的基本单位,线程是调度CPU的基本单位,一个进程至少包含一个执行线程,线程寄生在进程当中。每个线程都有一个程序计数器(记录要执行的下一条指令),一组寄存器(保存当前线程的工作变量),堆栈(记录执行历史,其中每一帧保存了一个已经调用但未返回的过程)
- 线程分为两类:
- 用户级线程(User-Level Thread)
- 内核线线程(Kernel-Level Thread)
用户空间划分:
* 内核空间
* 用户空间
-
Java线程与内核线程的关系
-
线程的生命状态
并发
并发的优势 : 充分利用多核CPU的计算能力 2、方便进行业务拆分,提升应用性能
并发产生的问题 : 高并发场景下,导致频繁的上下文切换临界区线程安全问题,容易出现死锁的,产生死锁就 会造成系统功能不可用
JMM 模型
JMM与JVM内存区域的划分是不同的概念层次,更恰当说JMM描述的是一组规则,通过这组规则控制程序中各个变量在共享数据区域和私有数据区域的访问方式,JMM是围绕原子性,有序性、可见性展开。
- 主内存: 主要存储的是Java实例对象,所有线程创建的实例对象都存放在主内存中,不管该实例对 象是成员变量还是方法中的本地变量(也称局部变量),当然也包括了共享的类信息、常量、静 态变量。由于是共享数据区域,多条线程对同一个变量进行访问可能会发生线程安全问题。
- 工作内存: 主要存储当前方法的所有本地变量信息(工作内存中存储着主内存中的变量副本拷贝),每 个线程只能访问自己的工作内存,即线程中的本地变量对其它线程是不可见的,就算是两个线 程执行的是同一段代码,它们也会各自在自己的工作内存中创建属于当前线程的本地变量,当 然也包括了字节码行号指示器、相关Native方法的信息。注意由于工作内存是每个线程的私有 数据,线程间无法相互访问工作内存,因此存储在工作内存的数据不存在线程安全问题。
Java内存模型内存交互操作
- Java内存模型内存同步规则
- 不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中
- 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或者assign)的变量。即就是对一个变量实施use和store操作之前,必须先自行assign和load操作。
- 一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现。
- 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量之前需要重新执行load或assign操作初始化变量的值。
- 如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
- 对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)
volatile原理与内存语义
- volatile是Java虚拟机提供的轻量级的同步机制
- volatile语义有如下两个作用
- 可见性:保证被volatile修饰的共享变量对所有线程总数可见的,也就是当一个线程修改了一个被volatile修饰共> 享变量的值,新值总是可以被其他线程立即得知。
- 有序性:禁止指令重排序优化。
- volatile缓存可见性实现原理
- JMM内存交互层面:volatile修饰的变量的read、load、use操作和assign、store、write必须是连续的,即修改后必须立即同步会主内存,使用时必须从主内存刷新,由此保证volatile变量的可见性。
- 底层实现:通过汇编lock前缀指令,它会锁定变量缓存行区域并写回主内存,这个操作称为“缓存锁定”,缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据。一个处理器的缓存回写到内存内存会导致其他处理器的缓存无效
并发编程三大特性
- 可见性
- 原子性
- 有序性
- volatile保证可见性与有序性,但是不能保证原子性,要保证原子性需要借助synchronized、Lock锁机制,同理也能保证有序性与可见性。因为synchronized和Lock能够保证任一时刻只有一个线程访问该代码块。