更新器类
AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater基于反射的实用工具,可以对指定类的指定volatile 字段进行原子更新
约束
- 只能是实例变量
- 字段必须声明是volatile类型
- 字段不能是private,不然访问不到
- 对于AtomicIntegerFieldUpdater 和AtomicLongFieldUpdater 只能修改int/long类型的字段
- 如果申明 AtomicIntegerFieldUpdater对象是static类型,最好一起申明final类型.避免AtomicIntegerFieldUpdater被其他线程赋值.本来就是安全原子设计的考虑.
AtomicLong和AtomicLongFieldUpdater
第一次看到是在看Druid框架里,第一反应是AtomicLong和AtomicLongFieldUpdater 有什么区别.
相同
都是对一个变量进行原子操作.最终都保证了一个变量的原子性
不同
AtomicLongFieldUpdater
计数器保证原子性的手段未必是cas
操作.而AtomicLong
一定是unsafe
包下的cas
方法执行.
目前我暂时没有发现不支持cas操作的jvm.
AtomicLongFieldUpdater
- 判断
AtomicLong.VM_SUPPORTS_LONG_CAS
- 执行
CASUpdater
或者LockedUpdater
@CallerSensitive
public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,String fieldName) {
Class<?> caller = Reflection.getCallerClass();
// 如果支持Long类型的cas操作 则执行CASUpdater
if (AtomicLong.VM_SUPPORTS_LONG_CAS)
return new CASUpdater<U>(tclass, fieldName, caller);
else
return new LockedUpdater<U>(tclass, fieldName, caller);
}
CASUpdater
Cas更新操作和我们之前认知的都一致.只是与AtomicLong一致,使用的是unsafe包下的原子操作.这部分能力由C语言提供
public final boolean compareAndSet(T obj, long expect, long update) {
accessCheck(obj);
return U.compareAndSwapLong(obj, offset, expect, update);
}
public final boolean weakCompareAndSet(T obj, long expect, long update) {
accessCheck(obj);
return U.compareAndSwapLong(obj, offset, expect, update);
}
public final void set(T obj, long newValue) {
accessCheck(obj);
U.putLongVolatile(obj, offset, newValue);
}
public final void lazySet(T obj, long newValue) {
accessCheck(obj);
U.putOrderedLong(obj, offset, newValue);
}
public final long get(T obj) {
accessCheck(obj);
return U.getLongVolatile(obj, offset);
}
public final long getAndSet(T obj, long newValue) {
accessCheck(obj);
return U.getAndSetLong(obj, offset, newValue);
}
public final long getAndAdd(T obj, long delta) {
accessCheck(obj);
return U.getAndAddLong(obj, offset, delta);
}
LockedUpdater
LockedUpdater使用的是synchronized锁.jvm级别的锁.性能上不如Cas.由于没有Cas函数的能力,所以进行了读,判断旧值,赋值,写等动作.
public final boolean compareAndSet(T obj, long expect, long update) {
accessCheck(obj);
synchronized (this) {
long v = U.getLong(obj, offset);
if (v != expect)
return false;
U.putLong(obj, offset, update);
return true;
}
}
public final boolean weakCompareAndSet(T obj, long expect, long update) {
return compareAndSet(obj, expect, update);
}
public final void set(T obj, long newValue) {
accessCheck(obj);
synchronized (this) {
U.putLong(obj, offset, newValue);
}
}
public final void lazySet(T obj, long newValue) {
set(obj, newValue);
}
public final long get(T obj) {
accessCheck(obj);
synchronized (this) {
return U.getLong(obj, offset);
}
}
总结
AtomicLongFieldUpdater的精髓在于newUpdater,我在这里解释为更新器.这是他与AtomicLong最大的不同.即便他们底层做的都是一样的逻辑
可读性
对比原本AtomicLong
的命名,大概率不具备计数器的意思,阅读起来并不知道哪些值是需要代码里去计算的.此时新增一个AtomicLongFieldUpdater
类型的计数器.赋予更恰当的名称,可以改善上述情况
设计性
如果现在有一个需求,将要原来某个类中long类型进行计数,例如现在需要对 Report
对象中的registerCount
进行计数.并且程序中有多处set操作.
如果我把registerCount
字段从 long
改成AtomicLong
,那么程序不会报错,但是没有保证原子性.毕竟原本的set操作是直接将newValue设置进去.而读取时也没有保证内存的可见性(当然可见性还是比较容易的 声明下volatile
就可以了).
所以还是新增一个成员变量
private AtomicLong registerCount2;
那么在所有原先对registerCount
进行写入的地方进行registerCount2.incrementAndGet()
操作.最后读取registerCount
2就可以了.
可是真的可以么.也许我修改的这个类是一个和数据库交互的持久层对象,我在持久层对象增加一个成员变量,需要修改很多额外的工作.一方面是去跟持久层解释,这个成员变量麻烦你不要给我映射.另外一方面我又要再这个POJO
中操作他.
如果是这样,我会更期望可以新增一个类,在这个类中去引用需要计数的另外一个对象.那么AtomicLongFieldUpdater
就变得有意义.
通过AtomicLongFieldUpdater
传入需要统计的对象,并且指定统计该对象的字段.将统计操作与原本对象所属行为解耦.更符合开闭原则
健壮性
通过阅读源码,我们可以发现 AtomicLongFieldUpdater
帮助我们判断了当前的JVM是否支持CAS函数
,如果不支持则会使用LockUpdater
去完成该动作.那么使用AtomicLongFieldUpdater
理论上会使我们的程序更加健壮.