《深入理解Java虚拟机》读书笔记——Java内存模型

概述

由于计算机的存储设备与处理器的运算速度有几个数量级的差距,所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存来作为内存与处理器之间的缓冲:将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存块中,这样处理器就无须等待缓慢的内存读写了。

这样虽然很好地解决了处理器与内存速度的矛盾,但是也引入了一个新的问题:缓存一致性。在多处理器系统中,每个处理器都有自己的高速缓存,而它们又共享同一主内存。当多个处理器的运算任务涉及到同一块主内存区域时,将可能导致各自的缓存数据不一致。因此,需要各个处理器访问缓存时遵循一些协议,在读写时要根据协议来进行操作。

Java内存模型

主内存与工作内存

Java内存模型规定了所有的变量都存储在主内存中,每个线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需通过主内存来完成。

内存间交互操作

Java内存模型定义了8种操作来完成主内存和工作内存之间的交互:

  1. lock:作用于主内存的变量,把变量标识为一条线程独占的状态。
  2. unlock:作用于主内存的变量,把处于锁定状态的变量释放出来,释放后的变量才能被其他线程锁定。
  3. read:作用于主内存的变量,把变量值从主内存传输到线程的工作内存中,以便随后的load动作使用。
  4. load:作用于工作内存的变量,把read操作从主内存中得到的变量值放入工作内存的变量副本中。
  5. use:作用于工作内存的变量,把工作内存中一个变量的值传递给执行引擎。
  6. assign:作用于工作内存的变量,把一个从执行引擎接收到的值赋给工作内存的变量。
  7. store:作用于工作内存的变量,把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。
  8. write:作用于主内存的变量,把store操作从工作内存中得到的变量的值放入主内存的变量中。

如果要把一个变量从主内存复制到工作内存,就要顺序执行read和load操作;如果要把变量从工作内存同步回主内存,就要顺序执行store和write操作。java内存模型只要求上述两个操作必须按顺序执行,而没有保证是连续执行。

Volatile

volatile可以说是Java虚拟机提供的最轻量级的同步机制。当一个变量定义为volatile后,它将具备两种特性,第一是保证变量对所有线程的可见性(当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的,普通变量无法做到这一点,普通变量的值在线程间传递均需通过主内存);第二是禁止指令重排序。

对volatile型变量进行read,load,use,assign,store和write操作时需要满足如下规则:

  • use动作和load,read动作必须连续一起出现。这条规则要求在工作内存中,每次使用变量前都必须先从主内存刷新最新的值,用于保证能看见其他线程对变量所做的修改后的值。
  • assign动作和store,write动作必须连续一起出现。这条规则要求在工作内存中,每次修改变量后都必须立即同步回主内存中,用于保证其他线程可以看到自己对变量的修改。