AtomicReferenceFieldUpdater — 리플렉션 기반 원자적 필드 업데이터
AtomicReferenceFieldUpdater — 리플렉션 기반 원자적 필드 업데이터
AtomicReferenceFieldUpdater<T,V>는 지정된 클래스의 지정된 volatile 참조 필드를 원자적으로 업데이트할 수 있게 해주는 리플렉션 기반 유틸리티예요. 객체 안의 개별 필드를 통째로 원자적 자료구조로 만들고 싶은데, 매번 클래스 전체를 원자적 wrapper로 감싸기 부담스러울 때 유용해요.
본문
도입 — 왜 필요한가
같은 노드(node)의 여러 참조 필드가 각각 독립적으로 원자적 업데이트를 받아야 할 때가 있어요. 예를 들어 트리 노드를 아래처럼 선언하면, left/right 같은 필드를 따로따로 원자적으로 바꿀 수 있어요.
class Node {
private volatile Node left, right;
private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
private static final AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
Node getLeft() { return left; }
boolean compareAndSetLeft(Node expect, Node update) {
return leftUpdater.compareAndSet(this, expect, update);
}
// ... and so on
}
주의할 점은 기존 원자적 클래스들보다 compareAndSet의 보장이 약하다는 거예요. 이 클래스는 필드의 모든 사용이 원자적 접근에 적합한지 보장할 수 없기 때문에, 같은 업데이터에 대한 다른 compareAndSet/set 호출에 한해서만 원자성을 보장해요.
또한 newUpdater에 넘긴 클래스의 인스턴스가 아닌 객체를 T 타입 파라미터로 넘기면 ClassCastException이 던져져요.
생성자
protected AtomicReferenceFieldUpdater()
서브클래스가 사용할 protected do-nothing 생성자예요.
업데이터 생성
public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName)
주어진 필드를 가진 객체를 위한 업데이터를 만들어 반환해요. 리플렉션 타입과 제네릭 타입이 일치하는지 확인하기 위해 Class 인자가 필요해요.
tclass— 필드를 가진 객체의 클래스vclass— 필드의 클래스fieldName— 업데이트할 필드 이름ClassCastException— 필드 타입이 잘못된 경우IllegalArgumentException— 필드가volatile이 아닌 경우RuntimeException— 클래스가 필드를 갖지 않거나, 타입이 틀렸거나, Java 언어 접근 통제상 호출자에게 필드가 접근 불가능한 경우(중첩된 리플렉션 예외 포함)
원자적 갱신
public abstract boolean compareAndSet(T obj, V expect, V update)
객체의 현재 필드 값이 == 기대값일 때만 update로 원자적으로 설정해요. 성공하면 true를 반환해요. 같은 업데이터의 compareAndSet/set 호출에 대해 원자성이 보장돼요.
obj— 필드를 조건부로 설정할 객체expect— 기대값update— 새 값
public abstract boolean weakCompareAndSet(T obj, V expect, V update)
compareAndSet과 유사하지만 **가짜 실패(spurious failure)**가 가능하고 순서 보장이 없어요. compareAndSet의 대안으로는 드물게 적절해요.
public abstract void set(T obj, V newValue)
객체의 필드를 주어진 newValue로 설정해요. 이후의 compareAndSet 호출에 대해 volatile store처럼 동작이 보장돼요.
public abstract void lazySet(T obj, V newValue) — 필드를 주어진 값으로 "결국(Eventually)" 설정해요. (JDK 1.6+)
public abstract V get(T obj) — 객체의 필드 현재 값을 반환해요.
public V getAndSet(T obj, V newValue) — 필드를 주어진 값으로 원자적으로 설정하고 이전 값을 반환해요.
함수 적용 계열
public final V getAndUpdate(T obj, UnaryOperator<V> updateFunction) — 함수 적용 결과로 필드를 원자적으로 갱신하고 이전 값을 반환해요. 함수는 스레드 경합 시 재적용될 수 있어 부작용이 없어야 해요. (JDK 1.8+)
public final V updateAndGet(T obj, UnaryOperator<V> updateFunction) — 같은 방식으로 갱신하되 갱신된 값을 반환해요. (JDK 1.8+)
public final V getAndAccumulate(T obj, V x, BinaryOperator<V> accumulatorFunction) — 현재 값과 x에 함수를 적용한 결과로 갱신하고 이전 값을 반환해요. 함수는 현재 값이 첫 번째 인자, 주어진 값이 두 번째 인자로 적용돼요. 부작용 없는 2-인자 함수여야 해요. (JDK 1.8+)
public final V accumulateAndGet(T obj, V x, BinaryOperator<V> accumulatorFunction) — 같은 방식으로 갱신하되 갱신된 값을 반환해요. (JDK 1.8+)