主内存和工作内存
主内存是所有变量存储的地方,工作内存是当前线程的中要使用变量的主内存的副本,线程对变量的操作就在工作内存里面完成,不能直接修改主内存的变量,不同线程不能直接读写对方工作内存的变量,之间交互必须通过主内存来完成。
内存之间的交互操作
虚拟机定义了8种原子操作来完成工作内存和主内存的交互。
lock:将主内存中一个变量标识为一个线程独占的状态。
unlock:将主内存中被锁住的变量解锁。
read:将一个变量值从主内存中传输到线程的工作内存中去。
load:将read操作读取的值放入到工作内存的变量副本中去。
use:将工作内存中一个变量的值传递给执行引擎,当虚拟机需要使用时就会执行这个操作。
assign:将执行引擎的值赋值给工作内存的变量。
store:将工作内存中的值传到主内存中去。
write:将从工作内存中得到的值放入到主内存的变量中。
同时有以下规则:
1.不许read和load,store和write分开执行。
2.不许线程丢弃assign操作,也就是在工作内存中改变了值,必须同步到主内存中去。
3.不许一个线程在没有发生assign的操作下就将数据从工作内存同步到主内存中去。
4.一个变量在同一时刻只许一个线程对其lock.
5.如果对一个变量lock,就会清空工作内存中该变量的值,在执行引擎使用这个变量前,需要重洗load和assign初始化这个变量的值。
6.不许对其他线程或者没有lock的线程执行unlock。
7.对变量执行unlock之前要先将变量同步到主内存中去。
volatile关键字
可见性:当一个线程修改这个变量的值后,新值对其他变量是可见的。
禁止指令重排序:指令重排序是在单线程下优化字节码的执行顺序,但是在多线程下可能出现问题,可以看本博客的单例模式下2重锁问题的解释为何要加volatile关键字。这个关键字通过内存屏障来禁止指令重排序。对于加锁和这个关键字,能用这个关键字的就不加锁,看你的业务场景吧。
这个关键字通过以下规则保证可见性和禁止重排序。
1.每次使用volatile变量时必须先从主内存中刷新读取最新的值。
2.每次修改volatile变量时,必须立刻同步数据到主内存。