在之前的文章中,我们了解到了计算机为什么会出现指令重排、指令重排引起的问题、为了解决指令重排而引入的缓存一致性和内存屏障等。
那么既然在多核时代计算机已经保证了执行结果的正确性,是不是对于JVM就不用去考虑这些东西了呢?
答案当然不是。首先,因为不同的硬件架构所实现的缓存一致性并不相同,JVM需要将这些实现进行统一;其次,缓存一致性协议只是保证了CPU缓存层面的可见性问题,然而Java多线程模型中,在线程栈内自己维护一份缓存是常见的优化措施,这部分工作内存还包括内存中的一部分(Java内存模型和计算机硬件内存架构是一个交叉关系),显然缓存一致性协议并不能解决不同线程之间在内存中的一致性问题;最后,是由于编译器的导致的重排序问题。
Java是通过volatile、synchronized和锁来解决以上的问题的
Java 工作内存和主内存的交互
Java通过几种原子操作完成工作内存和主内存的交互:
- lock:作用于主内存,把变量标识为线程独占状态。
- unlock:作用于主内存,解除独占状态。
- read:作用主内存,把一个变量的值从主内存传输到线程的工作内存。
- load:作用于工作内存,把read操作传过来的变量值放入工作内存的变量副本中。
- use:作用工作内存,把工作内存当中的一个变量值传给执行引擎。
- assign:作用工作内存,把一个从执行引擎接收到的值赋值给工作内存的变量。
- store:作用于工作内存的变量,把工作内存的一个变量的值传送到主内存中。
- write:作用于主内存的变量,把store操作传来的变量的值放入主内存的变量中。