AtomicLongFieldUpdater、AtomicLong、Volatile

AtomicLongFieldUpdater、AtomicLong、Volatile

閱讀本文約花費: 3 (分鐘)

初次认识AtomicLongFieldUpdater这个类是在druid源码中看到的,当时很陌生又很好奇,druid中源码是这样的:

final static AtomicLongFieldUpdater<DruidAbstractDataSource> executeQueryCountUpdater = AtomicLongFieldUpdater.newUpdater(DruidAbstractDataSource.class, "executeQueryCount");

JavaCopy

定义的一个静态的且不可修改引用的类成员变量,从定义的名称“executeQueryCountUpdater”可以看出来,它是用于执行计数用的。但一时又不明白为什么这样用,它的优点在哪里,为什么不直接用AtomicLong呢,它也是可以原子更新的,线程安全的。于是我搜了一下executeQueryCount,发现类中有这个名称定义的另一个成员变更,源码中是这样定义的:

protected volatile long executeQueryCount = 0L;

JavaCopy

这个成员变量是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);
  }

JavaCopy

可以清楚的看到两个关键类CASUpdaterLockedUpdater,它们是AtomicLongFieldUpdater的内部类,且都继承自 AtomicLongFieldUpdater。当JVM支持CAS时,则使用CAS指令来原子的更新字段值;否则采用同步锁来更新字段值。到这里我也就明白了这个类的作用了,它就是为了原子的更新executeQueryCount的值,我推测这么写的是实现了读写分离的作用,即当executeQueryCount的值更新时,也保证了其它线程读取它的值一定是最新的,避免了同步阻塞,提升了性能。从而也明白了为什么不直接使用AtomicLong的原因了,AtomicLong常用的方法是incrementAndGet(getAndIncrement)decrementAndGet(getAndDecrement),它们的作用也是更新并返回其最新的值,这些方法的内部仍是使用的CAS的方式原子的更新其值,是线程阻塞的。

Rate this post

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注