java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作,以及堪比C语言的操作内存的方便性。但是在生产环境下不建议使用,本文主要是通过Unsafe工具来更深刻的理解Java源码的实现原理。
这篇博文主要讲通过双寄存器模式操作java堆对象上变量域的方法
getUnsafe()单例模式获取Unsafe对象
用户代码调用此方法将抛出安全异常,但是可以通过反射获取
CAS操作系列
CAS操作提供了硬件级别操作内存读写和锁的语义,在多处理器系统中,通过硬件指令组合:Lock + cmpxchg 来实现对一组先读后写的内存操作的原子性(不被其他线程中断),同时具有volatile变量读写的内存语义。lock指令用来刷新主内存,cmpxchg 指令进行接下来的读写,这两条指令保证了CAS操作的原子性和值更新的可见性,但是不保证接下来的对普通变量的访问能读到最新的值,所以一般CAS搭配volatile变量一起使用,从而始终都能保证读到最新的值,而不是仅仅CAS更新的时候。
所以通常情况下 CAS + volatile 搭配使用
volatile变量读写语义的操作系列
对对象的普通域进行具有volatile读/写的语义的操作
volatile写语义的延迟操作系列
需要注意的是:此方法组的含义使用来操作volatile变量域,实现了延迟操作的功能呢,即方法操作的变量域只有下次被以volatile读写的形式被访问之前,putOrderedxxx方法系列才会刷新缓存,这将使得volatile变量快速的写操作被允许,将volatile写性能消耗延迟到下一次volatile变量的读/写前发生。在下一次volatile读写前,当前操作的结果不保证线程间可见性。(描述错误,应该能保证可见性,见上面分析)
普通变量域的读写语义操作
此方法组不具备volatile读写的内存语义,也不具备volatile延迟写的内存语义。即使操作的域变量被volatile修饰,也不会立即刷新到主内存,更不会延迟刷新。不保证内存的可见性。
需要注意:volatile变量域与Unsafe的对象域读写之间的关系
不管变量域是否被volatile修饰,在内存中存储对象时都是不知道的,而Unsafe工具是在运行时操作内存对象的,所以要通过需要的内存语义来选择Unsafe工具方法。