정의
AtomicReference란 무엇인가
핵심은 락(synchronized) 없이도 CAS(Compare-And-Set)라는 CPU 원자 연산을 이용해 “현재 값이 예상한 값이면 새 값으로 바꾸기”를 안전하게 수행한다는 점입니다.
동작 원리
CAS(Compare-And-Set)로 락 없이 경쟁을 해결한다
CAS 한 줄 요약
메모리 가시성(Visibility) 감각
언제 쓰나
AtomicReference가 잘 맞는 4가지 시나리오
1) 불변 객체 스냅샷 교체
2) 상태 머신(State Machine)
3) 락을 피하고 싶은 경량 경쟁 구간
4) “한 번만” 초기화(Lazy init) 가드
원자적으로 “스냅샷”을 교체하면 읽기/쓰기 경계가 명확해집니다.
AtomicReference는 “참조”만 원자적입니다. 객체 내부 필드를 동시에 안전하게 바꿔주지 않습니다.
구현
Java 예제로 보는 AtomicReference 패턴
1) 가장 기본: get/set/compareAndSet
import java.util.concurrent.atomic.AtomicReference;
public class AtomicRefBasic {
public static void main(String[] args) {
AtomicReference<String> ref = new AtomicReference<>("A");
String v1 = ref.get(); // "A"
ref.set("B"); // B로 교체
boolean ok = ref.compareAndSet("B", "C"); // 현재가 B면 C로
System.out.println(ok); // true
System.out.println(ref.get()); // "C"
}
}
2) 정석 패턴: CAS 루프 (락-프리 갱신)
import java.util.concurrent.atomic.AtomicReference;
public class AtomicRefCasLoop {
static class State {
final int count; // 불변
State(int count) { this.count = count; }
State inc() { return new State(count + 1); }
}
public static void main(String[] args) {
AtomicReference<State> ref = new AtomicReference<>(new State(0));
for (;;) {
State cur = ref.get();
State next = cur.inc();
if (ref.compareAndSet(cur, next)) break; // 성공할 때까지 재시도
}
System.out.println(ref.get().count); // 1
}
}
3) 더 깔끔하게: updateAndGet (내부적으로 CAS 루프)
import java.util.concurrent.atomic.AtomicReference;
public class AtomicRefUpdateAndGet {
static class Config {
final String mode;
final int timeoutMs;
Config(String mode, int timeoutMs) {
this.mode = mode;
this.timeoutMs = timeoutMs;
}
Config withTimeout(int ms) { return new Config(mode, ms); }
}
public static void main(String[] args) {
AtomicReference<Config> cfg = new AtomicReference<>(new Config("prod", 1000));
Config newCfg = cfg.updateAndGet(old -> old.withTimeout(1500));
System.out.println(newCfg.timeoutMs); // 1500
}
}
주의사항
AtomicReference를 “정말 안전하게” 쓰기 위한 함정 3가지
1) AtomicReference는 “참조”만 원자적이다
2) ABA 문제(advanced)
3) 경쟁이 심하면 “스핀 비용”이 커질 수 있다
요약
체크리스트로 마무리