compareAndSet实现原理
compareAndSetHead
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
首先,用到了unsafe类,(Unsafe类是在sun.misc包下,不属于Java标准。但是很多Java的基础类库,包括一些被 广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty、Hadoop、Kafka等;Unsafe可认为是Java中留 下的后门,提供了一些低层次操作,如直接内存访问、线程调度等)
然后调用了compareAndSwapObject这个方法
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4,
Object var5);
这个是一个native方法
var1:需要改变的对象。
var2:偏移量(即之前求出来的headOffset的值)。
var4:期待的值。
var5:更新后的值。
整个方法的作用是如果当前时刻的值等于预期值var4,则更新为新的期望值 var5,如果更新成功,则返回
true,否则返回false;(当前线程想要修改的对象是否已经被其他线程修改,没有修改则修改为更新后的新值。)
对headOffset解析:
这里传入了一个headOffset,这个headOffset是什么呢?在下面的代码中,通过unsafe.objectFieldOffset然后通过反射获取了AQS类中的成员变量,并且这个成员变量被volatile修饰的。
headOffset这个是指类中相应字段在该类的偏移量,在这里具体即是指head这个字段在AQS类的内存中相对于该
类首地址的偏移量。
一个Java对象可以看成是一段内存,每个字段都得按照一定的顺序放在这段内存里,通过这个方法可以准确地告诉 你某个字段相对于对象的起始内存地址的字节偏移。用于在后面的compareAndSwapObject中,去根据偏移量找 到对象在内存中的具体位置
这个方法在unsafe.cpp文件中,代码如下
所以其实compareAndSet这个方法,最终调用的是unsafe类的compareAndSwap,这个指令会对内存中的共享数 据做原子的读写操作。
- 首先, cpu会把内存中将要被更改的数据与期望值做比较
- 然后,当两个值相等时,cpu才会将内存中的对象替换为新的值。否则,不做变更操作
- 最后,返回操作执行结果
很显然,这是一种乐观锁的实现思路。