锁在保证可见性的方法:刷新处理器缓存和冲刷处理器缓存。
- 刷新处理器缓存:保证了该锁的当前持有线程能够读取到前一个线程对这些数据所做的更新
- 冲刷处理器缓存:保证了该锁的持有线程对这些数据所做的更新对该锁的后续持有线程可见。
java虚拟机实际上是借助内存屏障来实现上述的两个动作。
内存屏障是被插入到两个指令之间进行使用的,其作用是禁止编译器、处理器重排序从而保障有序性。
- 按照可见性保障来划分,内存屏障可分为加载屏障(Load Barrier)和存储屏障(Store Barrier)。
-
- 加载屏障的作用是刷新处理器缓存,存储屏障的作用冲刷处理器缓存。Java虚拟机会在MonitorExit(释放锁)对应的机器码指令之后插入一个存储屏障,这就保障了写线程在释放锁之前在临界区中对共享变量所做的更新对读线程的执行处理器来说是可同步的。
- JAVA虚拟机会在MonitorEnter(申请锁)对应的机器码指令之后临界区开始之前的地方插入一个加载屏障,这使得读程序的执行处理器能够将写线程对相应共享变量所作的更新从其他处理器同步到该处理的高速缓存中。
- 按照有序性保障来划分:可分为获取屏障(Acquire Barrier)和释放屏障(Release Barrier)
-
- 获取屏障:在一个读操作之后插入该内存屏障,其作用是禁止该读操作与其后的任何读写操作之间进行重排序,这相当于进行的后续操作之前先要获得相应共享数据的所有权。
- 释放屏障:在写操作之前插入该内存屏障,其作用是禁止该写操纵与其前面的任何读操作进行重排序,这相当于在对应共享数据操作结束后释放所有权。
-
- Java虚拟机会在MonitorEnter对应的机器码指令之后临界区开始之前的地方插入一个获取屏障,并在临界区结束之后MonitorExit对应的机器码指令之前的地方插入一个释放屏障。