在介绍Java内存模型之前,先来看一下到底什么是计算机内存模型。
学习计算机的主要组成学习缓存的作用
冯诺依曼,提出计算机由五大组成部分,输入设备,输出设备存储器,控制器,运算器。
中央处理器,是计算机的控制和运算的核心,我们的程序最终都会变成指令让CPU去执行,处理程序中的数据。
我们的程序都是在内存中运行的,内存会保存程序运行时的数据,供CPU处理。
CPU的运算速度和内存的访问速度相差比较大。这就导致CPU每次操作内存都要耗费很多等待时间。内存的读写速度成为了计算机运行的瓶颈。==于是就有了在CPU和主内存之间增加缓存的设计==。最靠近CPU的缓存称为L1,然后依次是 L2,L3和主内存,CPU缓存模型如图下图所示。
CPU Cache分成了三个级别: L1, L2, L3。级别越小越接近CPU,速度也更快,同时也代表着容量越小。
1.L1是最接近CPU的,它容量最小,例如32K,速度最快,每个核上都有一个L1 Cache。
L2 Cache 更大一些,例如256K,速度要慢一些,一般情况下每个核上都有一个独立的L2 Cache。
L3 Cache是三级缓存中最大的一级,例如12MB,同时也是缓存中最慢的一级,在同一个CPU插槽之间的核共享一个L3 Cache。
Cache的出现是为了解决CPU直接访问内存效率低下问题的,程序在运行的过程中,CPU接收到指令后,它会最先向CPU中的一级缓存(L1 Cache)去寻找相关的数据,如果命中缓存,CPU进行计算时就可以直接对CPU Cache中的数据进行读取和写人,== 当运算结束之后,再将CPUCache中的最新数据刷新到主内存当中 ==,CPU通过直接访问Cache的方式替代直接访问主存的方式极大地提高了CPU 的吞吐能力。但是由于一级缓存(L1 Cache)容量较小,所以不可能每次都命中。这时CPU会继续向下一级的二级缓存(L2 Cache)寻找,同样的道理,当所需要的数据在二级缓存中也没有的话,会继续转向L3Cache、内存(主存)和硬盘。
计算机的主要组成CPU,内存,输入设备 ,输出设备。
学习Java内存模型的概念和作用
Java Memory Molde ( Java内存模型/JMM),千万不要和Java内存结构混淆
关于“Java内存模型”的权威解释,请参考 https://download.oracle.com/otn-pub/jcp/memory_model- 1.0-pfd-spec-oth-JSpec/memory_model-1_0-pfd-spec.pdf。
Java内存模型,是Java虚拟机规范中所定义的一种内存模型,Java内存模型是标准化的,屏蔽掉了底层不同计算机的区别。
Java内存模型是一套规范,描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节,具体如下。
主内存是所有线程都共享的,都能访问的。所有的 共享变量都存储于主内存 。
每一个线程有自己的工作内存,工作内存只存储该线程对共享变量的副本。线程对变量的所有的操作(读,取)都必须在工作内存中完成,而不能直接读写主内存中的变量,不同线程之间也不能直接访问对方工作内存中的变量。
Java内存模型是一套在多线程读写共享数据时,对共享数据的可见性、有序性、和原子性的规则和保障。
synchronized, volatile
通过对前面的CPU硬件内存架构、Java内存模型以及Java多线程的实现原理的了解,我们应该已经意识到,多线程的执行最终都会映射到硬件处理器上进行执行。
但Java内存模型和硬件内存架构并不完全一致。对于硬件内存来说只有寄存器、缓存内存、主内存的概念,并没有工作内存和主内存之分, 也就是说 Java 内存模型对内存的划分对硬件内存并没有任何影响,因为 JMM 只是一种抽象的概念,是一组 规则,不管是工作内存的数据还是主内存的数据,对于计算机硬件来说都会存储在计算机主内存中,当然也有可能存储到CPU缓存或者寄存器中,因此总体上来说,
Java内存模型和计算机硬件内存架构是一个相互交叉的关系,是一种抽象概念划分与真实物理硬件的交叉。
Java内存模型是一套规范,描述了 Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节 ,Java内存模型是对共享数据的可见性、有序性、和原子性的规则和保障。
了解主内存与工作内存之间的数据交互过程
Java内存模型中定义了以 下8种操作来完成 ,**主内存与工作内存之间具体的交互协议, 即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,虚拟机实现时必须保证下面提及的 每一种操作都是原子的、不可再分的。**对应如下的流程图:
每个线程都有一个工作内存,线程只可以修改自己工作内存中的数据,然后再同步回主内存,主内存由多个内存共享。
下面 8 个操作都是原子的,不可再分的:
1) lock:作用于 主内存 的变量,它把一个变量标识为一个线程独占的状态。
2) unlock:作用于 主内存 的变量,他把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
3) read:作用于 主内存 变量,他把一个变量的值从主内存传输到线程的工作内存,以便随后的 load 操作使用。
4) load:作用于 工作内存 的变量,他把 read 操作从主内存中得到的变量值放入工作内存的变量副本中。
5) use:作用于 工作内存 的变量,他把工作内存中一个变量的值传递给执行引擎,每 当虚拟机遇到一个需要使用到变量的值得字节码指令时将会执行这个操作。
6) assign:作用于 工作内存 的变量,他把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
7) store:作用于 工作内存 的变量,他把工作内存中一个变量的值传送到主内存中,以便随后 write 使用。
8) write:作用于 主内存 的变量,他把 store 操作从工作内存中得到的变量的值放入主内存的变量中。