引言
接下来是原子类序章中我们提到的原子更新字段类,它们是AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater。其实就是了原子的更新一个引用类型的整形字段、long型字段、引用类型字段。
AtomicIntegerFieldUpdater
首先根据如下的类结构可见,它本身是一个抽象方法,提供了一个静态工厂方法newUpdater()来生成实例。
public abstract class AtomicIntegerFieldUpdater{ @CallerSensitive public static AtomicIntegerFieldUpdater newUpdater(Class tclass, String fieldName) { return new AtomicIntegerFieldUpdaterImpl (tclass, fieldName, Reflection.getCallerClass()); } /** * Protected do-nothing constructor for use by subclasses. */ protected AtomicIntegerFieldUpdater() { } .....
接着来看它的实现类,它的实现类AtomicIntegerFieldUpdaterImpl是它的一个私有静态内部类:
private static class AtomicIntegerFieldUpdaterImplextends AtomicIntegerFieldUpdater { private static final Unsafe unsafe = Unsafe.getUnsafe(); private final long offset; private final Class tclass; private final Class> cclass; AtomicIntegerFieldUpdaterImpl(final Class tclass, final String fieldName, final Class> caller) { final Field field; final int modifiers; try { field = AccessController.doPrivileged( new PrivilegedExceptionAction () { public Field run() throws NoSuchFieldException { return tclass.getDeclaredField(fieldName); } }); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); ClassLoader cl = tclass.getClassLoader(); ClassLoader ccl = caller.getClassLoader(); if ((ccl != null) && (ccl != cl) && ((cl == null) || !isAncestor(cl, ccl))) { sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); } } catch (PrivilegedActionException pae) { throw new RuntimeException(pae.getException()); } catch (Exception ex) { throw new RuntimeException(ex); } Class> fieldt = field.getType(); if (fieldt != int.class) throw new IllegalArgumentException("Must be integer type"); if (!Modifier.isVolatile(modifiers)) throw new IllegalArgumentException("Must be volatile type"); this.cclass = (Modifier.isProtected(modifiers) && caller != tclass) ? caller : null; this.tclass = tclass; offset = unsafe.objectFieldOffset(field); } .....
从它的实例构造方法可见,它首先会对目标class及其指定的字段进行检测,主要是访问权限、数据类型是否是int,是否 是volatile修饰,最后当然还有通过unsafe获取目标字段的偏移量,为后面的CAS原子操作作准备。
从以上方法我们可以得出,要想使用AtomicIntegerFieldUpdater原子的更新一个对象的某个字段,必须满足以下条件:
- 调用者必须有对目标类的访问权限;
- 目标字段必须是整形int或者Integer;
- 目标字段必须是public修饰的;
- 目标字段必须是volatile修饰的。
另外,实现类AtomicIntegerFieldUpdaterImpl还实现了一些AtomicIntegerFieldUpdater的基础的原子更新的抽象方法:
public boolean compareAndSet(T obj, int expect, int update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.compareAndSwapInt(obj, offset, expect, update); } public boolean weakCompareAndSet(T obj, int expect, int update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.compareAndSwapInt(obj, offset, expect, update); } public void set(T obj, int newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putIntVolatile(obj, offset, newValue); } public void lazySet(T obj, int newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); unsafe.putOrderedInt(obj, offset, newValue); } public final int get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getIntVolatile(obj, offset); } public int getAndSet(T obj, int newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getAndSetInt(obj, offset, newValue); } public int getAndIncrement(T obj) { return getAndAdd(obj, 1); } public int getAndDecrement(T obj) { return getAndAdd(obj, -1); } public int getAndAdd(T obj, int delta) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); return unsafe.getAndAddInt(obj, offset, delta); } public int incrementAndGet(T obj) { return getAndAdd(obj, 1) + 1; } public int decrementAndGet(T obj) { return getAndAdd(obj, -1) - 1; } public int addAndGet(T obj, int delta) { return getAndAdd(obj, delta) + delta; }
这些方法和AtomicInteger提供的方法一致,不再熬述。剩下的其他的一些方法和AtomicInteger提供的原子更新方法几乎一样,都分为那四大原子更新方法,也不在一一列举。
AtomicLongFieldUpdater
再看AtomicLongFieldUpdater,它和AtomicIntegerFieldUpdater的结构基本一致,也是一个抽象方法,不同的是它是对long型字段的原子更新,而不是整形。
另外还有一个比较重要的区别就是,它的实现类有两个,根据平台是否支持8字节的CAS操作来选择不同的实现:
@CallerSensitive public static AtomicLongFieldUpdater newUpdater(Class tclass, String fieldName) { Class> caller = Reflection.getCallerClass(); if (AtomicLong.VM_SUPPORTS_LONG_CAS) return new CASUpdater(tclass, fieldName, caller); else return new LockedUpdater(tclass, fieldName, caller); }
如果平台支持8字节的CAS操作,那么实现逻辑 CASUpdater就和AtomicIntegerFieldUpdater中的实现类似,也就是直接使用CAS操作达到原子操作的目的,如果平台不支持8字节的CAS操作,那么就使用内部加锁的方式实现对8字节的原子更新操作,如下所示为当平台不支持8字节的CAS操作时的内部加锁实现方式:
public boolean compareAndSet(T obj, long expect, long update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { long v = unsafe.getLong(obj, offset); if (v != expect) return false; unsafe.putLong(obj, offset, update); return true; } } public boolean weakCompareAndSet(T obj, long expect, long update) { return compareAndSet(obj, expect, update); } public void set(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { unsafe.putLong(obj, offset, newValue); } } public void lazySet(T obj, long newValue) { set(obj, newValue); } public long get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); synchronized (this) { return unsafe.getLong(obj, offset); } }
可见当不支持8字节的CAS操作时,JDK8采用的是synchronized锁实现。
AtomicLongFieldUpdater和AtomicIntegerFieldUpdater一样,可以对所操作的字段进行加减和更复杂的函数式运算,具体方法和AtomicLong类似,不再一一列举了。
AtomicReferenceFieldUpdater
最后再看AtomicReferenceFieldUpdater,它同样是一个抽象类,也是通过一个工厂方法生成原子更新器实例,同样它的实现方法也是通过CAS实现,所要操作的字段也必须是特定类型的public volatile修饰的。
AtomicReferenceFieldUpdater比 AtomicReference的原子更新操作更细粒度和更精确,它比AtomicReference这种直接更新整个对象要高效的多。
测试代码:
public class AtomicIntegerFieldUpdaterTest { private static AtomicIntegerFieldUpdatera = AtomicIntegerFieldUpdater .newUpdater(User.class, "old"); public static void main(String[] args) { User user = new User("conan", 10); System.out.println(a.getAndIncrement(user)); //10 System.out.println(a.get(user)); //11 } public static class User { private String name; public volatile int old; public User(String name, int old) { this.name = name; this.old = old; } public String getName() { return name; } public int getOld() { return old; } } }