上一章中初步接触到了CAS的基础类AtomicInteger,那接下面我们要从源码角度分析内部如何保证安全的进行多线程调用。
AtomicInteger
变量引用句柄
//初始化变量,肯定得用volatile呀,想什么呢
private volatile int value;
- set/get方法都是非原子操作,直接读取通过句柄 修改/读取 变量表中值。
- 原子操作都是基于value的内存地址进行对比操作。
变量内存中地址
- 原子操作相关变量实例化与声明。
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
private static final long VALUE;
……
//static语句块,被类加载器加载时候调用,一个类只会触发一次
static {
try {
//通过反射getDeclaredField反射方法拿到当前类的value变量
//再通过objectFieldOffset拿到变量在内存的地址(相当于C语言的指针)
VALUE = U.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
- 原子操作的赋值方法
2.1 compareAndSet通过对比内存地址的变量是否与预期值相同,如果相同就把update新值更新上去。
public final boolean compareAndSet(int expect, int update) {
//VALUE是变量在内存的地址
return U.compareAndSwapInt(this, VALUE, expect, update);
}
总结
- 满怀热血想去看内部C代码如何实现的,发现google一圈都找不到资料。后续再自己弄一下吧。比较惭愧,并没有分析到内部的精髓所在。
- 如果需要多线程访问时,可以考虑下AQS+CAS结合来进行原子操作,这样对比而言,比加同步锁性能更好。
网友评论