java内存模型知识梳理
JMM前言
java内存模型,和并发编程有关(JMM—Java Memory Model)
是一组规范,需要各个jvm的实现来遵守jmm规范。
JMM结构
jmm包含五部分:
共有的:堆,方法区(static修饰对象)
私有的:栈,本地方法栈(native修饰),程序计数器
Java线程内存模型跟cpu的缓存模型类似,是基于cpu缓存模型来建立的。
所以结构组成:主内存—>多级缓存区—>工作内存
JMM必须要保证可见性、原子性、有序性
JMM遵循happens-before原则:第一个操作对于第二个操作是可见的。
可以使用volitale和synchronize解决。
Java内存模型只是一组规范,
Java 内存模型是个很复杂的规范,可以从不同的视角来解读,站在我们这些程序员的视角,本质上可以理解为,Java 内存模型规范了 JVM 如何提供按需禁用缓存和编译优化的方法。具体来说,这些方法包括 volatile、synchronized 和 final 三个关键字,以及六项Happens-Before 规则。
(可见性、原子性、有序性介绍)
原子性:原子性指的是一个操作不会被中断,操作不会受到其他线程的影响。两个线程同时对一个变量赋值,则该值要么是1要么是2,线程A和线程B互不干扰,不会被中断。
可见性:可见性指的是一个线程修改共享变量的值,其他线程能够马上得到这个修改的值。
有序性:序性指的是单线程中代码的执行总是按照循序执行的,多线程中可能出现乱序顺序,程序编译成字节码指令的时候可能会出现重排序现象,重排后的指令与原指令的顺序比一定一致。另一种角度:在一个线程内所有的操作都是有序的,但是在多线程下,一个线程观察另一个线程,所有的操作都是无序的,因为可能存在指令重排序和工作内存和主内存的同步延迟。编译器和处理器的重排序有编译器优化重排序,指令级并行重排序,即内存系统的重排序
JMM结构 以及运行流程
内存模型结构:
RAM:主存
cache:多级缓存区(每一层缓存的大小在缩小, 但读取速度在不断的增加,即L1最快缓存最少)
registers:寄存器(cpu通常从这获取数据)
线程的读写流程:
读:直接从寄存器中读取(如果被volatile修饰的变量,则直接从主内存读取)
写:写入主内存,并逐步缓存到各级缓存区以及寄存器之中。
volatile关键字
Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。
在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比sychronized关键字更轻量级的同步机制。
总结:
volitale不会缓存在寄存器以及其他处理器不可以见的地方,因此他直接从主内存进行读取。
volatile保证可见性和有序性,但是不保证原子性、保证原子性需要借助synchronized这样的锁机制