AtomicLongFieldUpdater、AtomicLong、volatile
初次认识AtomicLongFieldUpdater
这个类是在druid
源码中看到的,当时很陌生又很好奇,druid
中源码是这样的:
final static AtomicLongFieldUpdater<DruidAbstractDataSource> executeQueryCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "executeQueryCount");
定义的一个静态的且不可修改引用的类成员变量,从定义的名称“executeQueryCountUpdater
”可以看出来,它是用于执行计数用的。但一时又不明白为什么这样用,它的优点在哪里,为什么不直接用AtomicLong
呢,它也是可以原子更新的,线程安全的。于是我搜了一下executeQueryCount
,发现类中有这个名称定义的另一个成员变更,源码中是这样定义的:
protected volatile long executeQueryCount = 0L;
这个成员变量是long型,且使用了volatile
关键字修饰,被volatile
修饰的变量,如果值发生了变更,其他线程立马可见,避免出现脏读的现象。但是呢,如果对值要进行修改,因为volatile
并不能保证值是原子操作的,就需要对修改值的方法使用同步了。至于为什么使用AtomicLongFieldUpdater
,还是没有一个清醒的认识,于是看了一下这个类的源码,首先这个类是一个抽象类,类的注释是这样写的:
A reflection-based utility that enables atomic updates to designated fields of designated classes.
意思是这个类是基于反射的实用程序,可通过原子更新来指定类别的指定字段。它的作用就是原子的更新指定字段的值。
此类有一个静态方法,创建并返回给定字段的更新对象,源码如下:
public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,
String fieldName) {
Class<?> caller = Reflection.getCallerClass();
if (AtomicLong.VM_SUPPORTS_LONG_CAS)
return new CASUpdater<U>(tclass, fieldName, caller);
else
return new LockedUpdater<U>(tclass, fieldName, caller);
}
可以清楚的看到两个关键类CASUpdater
和LockedUpdater
,它们是AtomicLongFieldUpdater
的内部类,且都继承自 AtomicLongFieldUpdater
。当JVM支持CAS时,则使用CAS指令来原子的更新字段值;否则采用同步锁来更新字段值。到这里我也就明白了这个类的作用了,它就是为了原子的更新executeQueryCount
的值,我推测这么写的是实现了读写分离的作用,即当executeQueryCount
的值更新时,也保证了其它线程读取它的值一定是最新的,避免了同步阻塞,提升了性能。从而也明白了为什么不直接使用AtomicLong的原因了,AtomicLong
常用的方法是incrementAndGet(getAndIncrement)
和decrementAndGet(getAndDecrement)
,它们的作用也是更新并返回其最新的值,这些方法的内部仍是使用的CAS的方式原子的更新其值,是线程阻塞的。
本人水平有限,如果理解有错,还请广大网友不吝指教。
转载请注明出处:http://fetosoft.cn/archives/2020/03/14/171