AtomicLongFieldUpdater源码解析
AtomicLongFieldUpdater类介绍
AtomicLongFieldUpdater类是JDK提供的volatile long封装器。可以通过它来原子更新某些对象的volatile修饰的long字段。
看下面这个例子,假设NotUseAtomicLongFieldUpdate类有一个字段value,它在某些场景下需要具有原子更新的能力,但又不能使用AtomicLong(可以认为是出于节省空间的考虑)。这个时候,AtomicLongFieldUpdater就派上用场了。
1 | public class NotUseAtomicLongFieldUpdate implements Runnable { |
类图
主要属性
无。主要属性在CASUpdater或者LockedUpdater中。这里就拿CASUpdater的属性来说明
1 | private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); |
U: Unsafe类,实现CAS算法
offset:Field字段在整个AtomicIntegerFieldUpdaterImpl中的内存偏移。
cclass:如果字段受保护,cclass为调用者类的Class对象,否则cclass等于tclass
tclass:被操作对象类的Class对象
主要方法
newUpdater(Class,String)
1 | /** |
新建一个Updater返回。如果平台支持CAS,则返回CASUpdater否则返回LockedUpdater
AtomicLongFieldUpdater()
1 | /** |
空函数
compareAndSet(T,long,long)
1 | /** |
抽象函数,具体实现可看CASUpdater或者LockedUpdater。
weakCompareAndSet(T,long,long)
1 | /** |
抽象函数,具体实现可看CASUpdater或者LockedUpdater。
set(T,long)
1 | /** |
抽象函数,具体实现可看CASUpdater或者LockedUpdater。
lazySet(T,long)
1 | /** |
抽象函数,具体实现可看CASUpdater或者LockedUpdater。
long get(T)
1 | /** |
抽象函数,具体实现可看CASUpdater或者LockedUpdater。
getAndSet(T,long)
1 | /** |
获取当前的值,并且将当前值更新为newValue。这里是一个死循环,极端情况下,可能导致自旋过久。
getAndIncrement(T)
1 | /** |
获取当前值,返回。并把当前值加1,更新。这里是一个死循环,极端情况下,可能导致自旋过久。
getAndDecrement(T)
1 | /** |
获取当前值,返回。并把当前值减1,更新。这里是一个死循环,极端情况下,可能导致自旋过久。
getAndAdd(T,long)
1 | /** |
获取当前值,返回。并将当前值加上delta,更新当前值.这里是一个死循环,极端情况下,可能导致自旋过久。
incrementAndGet(T)
1 | /** |
将当前值加1并更新,返回当前值。这里是一个死循环,极端情况下,可能导致自旋过久。
decrementAndGet(T)
1 | /** |
将当前值减1并更新,返回当前值。这里是一个死循环,极端情况下,可能导致自旋过久。
addAndGet(T,long)
1 | /** |
将当前值加上delta,更新,并返回。这里是一个死循环,极端情况下,可能导致自旋过久。
getAndUpdate(T,LongUnaryOperator)
1 | /** |
返回当前值,并将单元函数应用于当前值,更新。这里是一个死循环,极端情况下,可能导致自旋过久。
updateAndGet(T,LongUnaryOperator)
1 | /** |
将当前值应用于单元函数,并更新,返回。这里是一个死循环,极端情况下,可能导致自旋过久。
getAndAccumulate(T,long,LongBinaryOperator)
1 | /** |
返回当前值,并对当前值和x应用双元函数,将得到的结果更新当前值。这里是一个死循环,极端情况下,可能导致自旋过久。
accumulateAndGet(T,long,LongBinaryOperator)
1 | /** |
对当前值和x应用双元函数,并将得到的结果更新至当前值,并返回。
CASUpdater源码
CASUpdater(Class, String,Class)
1 | CASUpdater(final Class<T> tclass, final String fieldName, |
从上述代码中可以看到,如果字段想要被AtomicLongFieldUpdater修改的话,必须要满足下面几个条件:
- 字段必须是volatile类型的,在线程之间共享变量时保证立即可见.eg:volatile long value = 3
- 字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。但是对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。
- 只能是实例变量,不能是类变量,也就是说不能加static关键字。
- 只能是可修改变量,不能使final变量,因为final的语义就是不可修改。实际上final的语义和volatile是有冲突的,这两个关键字不能同时存在。
- 对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。
accessCheck(T)
1 | /** |
确认obj是不是cclass的实例
throwAccessCheckException(T)
1 | /** |
compareAndSet(T,long,long)
1 | public final boolean compareAndSet(T obj, long expect, long update) { |
如果当前值是expect,就通过调用unsafe的cas相关算法,更新当前值为update,返回true,否则返回false。
weakCompareAndSet(T,long,long)
1 | public final boolean weakCompareAndSet(T obj, long expect, long update) { |
从父类的注释上看,这个方法的本意是,调用weakCompareAndSet方法时不能保证指令重排的发生,因此,这个方法有时候会毫无理由地失败。
但是当前实现就是compareAndSet。
set(T,long)
1 | public final void set(T obj, long newValue) { |
设置当前值为newValue
lazySet(T,long)
1 | public final void lazySet(T obj, long newValue) { |
该方法是“慢慢”地将对象的obj的fieldName字段设置为newValue。这就意味着有段时间,多线程环境下,会有线程读取到旧值。
get(T)
1 | public final long get(T obj) { |
获取当前值
getAndSet(T,long)
1 | public final long getAndSet(T obj, long newValue) { |
返回当前值,并将当前值更新为newValue
getAndAdd(T,long)
1 | public final long getAndAdd(T obj, long delta) { |
返回当前值,并将当前值加上delta
getAndIncrement(T)
1 | public final long getAndIncrement(T obj) { |
返回当前值,并将当前值加1
getAndDecrement(T)
1 | public final long getAndDecrement(T obj) { |
返回当前值,并将当前值减1
incrementAndGet(T)
1 | public final long incrementAndGet(T obj) { |
将当前值加1,并返回
decrementAndGet(T)
1 | public final long decrementAndGet(T obj) { |
将当前值减1,并返回
addAndGet(T,long)
1 | public final long addAndGet(T obj, long delta) { |
将当前值加上delta,并返回。
LockedUpdater
由于LockUpdater部分方法与CASUpdater相同,这里不再赘述。仅列出和CASUpdater实现不同的方法。
compareAndSet(T,long,long)
1 | public final boolean compareAndSet(T obj, long expect, long update) { |
这里和CASUpdater不同,这里使用了锁。在更新当前值的时候,先锁上当前实例,如果当前值不等于expect,返回false,否则调用unsafe接口,更新当前值为update。
weakCompareAndSet(T,long,long)
1 | public final boolean weakCompareAndSet(T obj, long expect, long update) { |
直接调用的compareAndSet方法
set(T,long)
1 | public final void set(T obj, long newValue) { |
更新当前值的时候锁住实例。
lazySet(T,long)
1 | public final void lazySet(T obj, long newValue) { |
直接调用set方法
get(T)
1 | public final long get(T obj) { |
取值的时候,锁住当前实例,再调用Unsafe的方法获取值。
应用
1 | public class NotUseAtomicLongFieldUpdate { |