同期データ構造の原子フィールドクラス

8627 ワード

もっと読む
ことばを引く
次に原子系の序章で述べた原子更新フィールド類です.それらはAtomicLongFieldUpdater、AtomicInteger FieldUpdater、AtomicReference FieldUpdaterです.つまり、原子の参照タイプを更新する整形フィールド、longフィールド、参照タイプフィールドです.
 
AtomicInteger FieldUpdater
まず次のようなクラス構造から見て、それ自体が抽象的な方法であり、例を生成するために静的な工場法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() {
}
.....
 次にその実装クラスを見てみると、その実装クラスはAtomicInteger FieldUpdaterImplのプライベート静的な内部クラスである:
private static class AtomicIntegerFieldUpdaterImpl
	extends 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);
	}
.....
その例示的な構成方法から、まずターゲットクラスと指定されたフィールドを検出し、主にアクセス権限、データタイプがintかどうか、volatile修飾かどうか、最後にはunsafeによってターゲットフィールドのオフセット量を取得し、後のCAS原子動作のために準備することができる.
上記の方法から、AtomicInteger FieldUpdater原子を使用するためには、オブジェクトのあるフィールドを更新するために、次の条件を満たす必要があるということが分かります.
  • 使用者は目標類に対するアクセス権限を持たなければならない.
  • ターゲットフィールドは整形intまたはIntegerでなければなりません.
  • ターゲットフィールドは、publicで修飾されなければならない.
  • ターゲットフィールドは、volatileでなければなりません.
  • また,AtomicInteger FieldUpdaterImplを実現するために,AtomicInteger FieldUpdaterの基礎となる原子更新の抽象的な方法もいくつか実現した.
    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が提供する原子更新方法とほとんど同じで、その四つの原子更新方法に分けられています.
     
    Atomic LongFieldUpdater
    AtomicLongFieldUpdaterを見ると、AtomicInteger FieldUpdaterの構造とほぼ一致しています.抽象的な方法でもあります.これは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はAtomicInteger FieldUpdaterと同様に、直接に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操作がサポートされていない場合、JDK 8はsynchronizedロックを採用して実現されることが分かります.
     
    AtomicLongFieldUpdaterはAtomicInteger FieldUpdaterと同様に、操作されたフィールドを加减し、より复雑な関数式演算を行うことができます.具体的な方法はAtomicLongと似ています.
     
    AtomicReferenceFieldUpdater
    最後にAtomicReferenceFieldUpdaterを見ると、同じ抽象的なクラスであり、同じ工場法によって原子更新器の例を生成します.同じ実現方法もCASによって実現されます.操作するフィールドも特定のタイプのpublic volatileで修飾されなければなりません.
     
    AtomicReference FieldUpdaterはAtomicReferenceの原子更新操作よりも微細で正確で、AtomicReferenceのような直接的な更新の全体のオブジェクトよりもはるかに効率的です.
     
    テストコード:
    public class AtomicIntegerFieldUpdaterTest {
    
        private static AtomicIntegerFieldUpdater a = 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;
            }
        }
    }