Java内存模型

»深入理解Java虚拟机读书笔记

目录:

计算机中的多处理器问题

在计算机中,由于计算机的存储设备与处理器的运算速度相差很大,所以,通常会在处理器和内存中加一个高速缓存来作为缓冲。将运算需要用到的数据复制到缓存中,让运算能快速进行,运算结束后,再将数据从缓存中同步回内存,这样处理器就无须等待缓慢的内存读写。

image

但是,这就引发了一个新的问题:缓存一致性问题。即在多处理器中,内一个处理器都有自己的一块缓存,但是他们又都共享同一块内存,当多个处理器运算任务都涉及到同一块主存区域时,可能导致各自的数据不一致。为此,各个处理器在访问缓存时需要遵循一些协议。

除了增加缓存之外,为了使处理器内部的运算单元能尽量被充分利用,处理器可能会对输入代码进行乱序执行优化,处理器会在计算之后将乱序执行的结果重组,保证该结果与顺序执行的结果一致。但是,如果存在一个计算任务依赖另一个计算任务的中间结果,那么其顺序不能靠代码的先后顺序来保证。预处理器的优化类似,JAVA虚拟机也有类似的指令重排序优化

java内存模型

java虚拟机规范中试图定义一种java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能达到一致性内存访问效果。

(1) 主内存与工作内存

java内存模型规定所有的变量(这里的变量不包括局部变量和方法参数,因为这两者是属于线程私有)都存储在主内存。每条线程有自己的工作内存,线程的工作内存保存了该线程使用到的变量的主内存的拷贝副本,线程对变量的所有操作都必须在工作内存中完成,而不能直接读写主内存中的变量,不同的线程也无法访问对方的工作内存,线程间变量值的传递需要通过主存来完成。

image

主内存可以对应Java堆中的对象实例数据部分,工作内存可以对应于虚拟机栈中的部分区域。或者,主内存对应于物理硬件的内存,为了获取更高的运行速度,虚拟机可能会让工作内存优先存储于寄存器和告诉缓存中。

(2) 内存间的交互操作

关于内存之间的交互操作,主要就是将变量从主内存中拷贝到工作内存,然后将工作内存的数据同步回主内存。

为此,java内存模型定义了8种原子操作来完成。

如果要把一个变量从主存中复制到工作内存,那么就要顺序执行read 和 load操作,如果要把一个变量从工作内存同步回主存,就要顺序执行store和write

volatile型的变量

关键字volatile是java虚拟机提供的最轻量级的同步机制,但是它大多数情况下并不能保证线程安全。

作用:

volatile能够实现线程安全的条件:运算结果并不依赖当前的值,或者确保只有单一的线程修改变量的值;变量不需要与其他的状态变量共同参与不变约束(条件判断?)

原子性、可见性和有序性

(1) 原子性

通常,基本数据类型的访问读写是原子性的,还有Synchronized同步块之间的操作是原子性

(2) 可见性

Java内存模型通过在变量修改后将新值同步回主存,在变量读取前从主存中刷新变量值这种方式来实现可见性。除了volatile还有synchronized和final能够实现可见性。

(3) 有序性

如果在本线程中观察,所有操作都是有序的,如果在一个线程中观察另一个线程,所有操作都是无序的。可以同volatile和synchronized来实现有序性。