5주차 Unit 2.4 — Atomic + CAS 알고리즘

Psj·2026년 5월 26일

F-lab

목록 보기
162/230

Unit 2.4 — Atomic + CAS 알고리즘

F-LAB JAVA · 5주차 · Phase 2 · 동시성 안전 도구 3종 비교
★ 마스터 Unit — 면접 핵심 (★★★) + Phase 2 완주 (Part A 동시성 완성)


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • CAS (Compare And Swap) 알고리즘 4단계 는?
  • Atomic 이 락 없이 원자성을 보장 하는 원리는?
  • CAS 의 "재시도 (retry)" 동작은?
  • 은행 잔액 예시 로 CAS 흐름은?
  • 3종 비교 매트릭스 (synchronized/volatile/Atomic) 는?
  • ABA 문제 란?
  • Atomic 이 synchronized 보다 빠른 이유는?
  • CAS 의 재시도가 무한 반복 될 수 있는가?
  • 주요 Atomic 클래스 는?

🎯 핵심 한 문장

CAS (Compare And Swap) 는 "현재 값을 읽고, 새 값을 계산한 뒤, 메모리의 값이 읽었던 값과 같으면 교체하고 다르면 재시도" 하는 알고리즘으로, Atomic 클래스는 이를 통해 락 없이 (논블로킹) 원자성을 보장한다.
CAS 4단계 — (1) 현재 값을 읽어 레지스터에 저장 (기대값 A), (2) 새 값 계산 (B), (3) 메모리의 값과 A 를 비교, (4) 같으면 B 로 교체 (성공), 다르면 다른 스레드가 이미 수정한 것이므로 재시도한다.
논블로킹 — synchronized 는 락을 잡고 다른 스레드를 BLOCKED 시키지만, CAS 는 락 없이 단일 CPU 명령 (compareAndSwap) 으로 시도하고 실패하면 재시도하므로 스레드가 대기하지 않는다.
3종 비교 — synchronized (가시성 ✅, 원자성 ✅, 락, 가장 느림), volatile (가시성 ✅, 원자성 ❌, 메모리 동기화, 빠름), Atomic (가시성 ✅, 원자성 ✅, CAS, 빠름) 이다.
ABA 문제 — 값이 A→B→A 로 바뀌면 CAS 는 변하지 않은 것으로 오인할 수 있으며, AtomicStampedReference (버전 태그) 로 해결한다.

비유 — 공유 메모장에 동시 수정

CAS = 공유 메모장 수정 (낙관적):

CAS 4단계:
  1. 현재 값 읽기: 메모장 보니 "100" (기대값 A=100)
  2. 새 값 계산: 100 + 50 = 150 (B)
  3. 비교: 지금도 "100" 인가?
  4-a. 같으면: "150" 으로 교체 (성공!)
  4-b. 다르면 (누가 바꿈): 다시 1번부터 (재시도)

은행 잔액 예시:
  스레드1: 100 읽음 → 150 시도 → 메모리 100 일치 → 성공 (150)
  스레드2: 100 읽음 → 150 시도 → 메모리 이미 150 → 실패
           → 재시도: 150 읽음 → 200 시도 → 성공 (200)

논블로킹 (대기 X):
  synchronized: 문 잠그고 (다른 사람 대기)
  CAS: 문 안 잠그고 시도, 충돌 시 다시 (대기 X)

ABA 문제:
  - 100 → 50 → 100 (왔다갔다)
  - "100 그대로네?" 착각
  - 버전 태그로 해결 (100#1 vs 100#3)

→ CAS = 읽기→계산→비교→교체/재시도 (낙관적, 논블로킹), Atomic 의 원리.


🧭 9개 섹션 로드맵

1. CAS 알고리즘 4단계
2. 락 없이 원자성 (논블로킹)
3. 재시도 동작
4. 은행 잔액 예시
5. 3종 비교 매트릭스
6. ABA 문제
7. Atomic이 빠른 이유
8. 주요 Atomic 클래스
9. 면접 + 자기 점검 + 마스터 50문항

1️⃣ CAS 알고리즘 4단계

1.1 CAS

CAS (Compare And Swap):

  현재 값과 기대값을 비교하여
  같으면 새 값으로 교체하는 원자적 연산.

  - 단일 CPU 명령
  - 락 없음

1.2 4단계

CAS 4단계:

1. 현재 값 읽기 → 레지스터 (기대값 A)
2. 새 값 계산 (B)
3. 메모리 값 == A 비교
4. 같으면 → B 로 교체 (성공)
   다르면 → 재시도

1.3 compareAndSet

// CAS 메서드
boolean compareAndSet(int expectedValue, int newValue);

// 동작:
// 현재 == expectedValue 면
//   → newValue 로 교체, true 반환
// 다르면
//   → 교체 X, false 반환 (재시도)

1.4 increment 구현 (개념)

// AtomicInteger.incrementAndGet (개념)
public int incrementAndGet() {
    int current, next;
    do {
        current = get();        // 1. 현재 값 (A)
        next = current + 1;     // 2. 새 값 (B)
    } while (!compareAndSet(current, next));   // 3,4. 비교+교체 (실패 시 재시도)
    return next;
}

1.5 하드웨어 지원

하드웨어 지원:

  CAS = CPU 명령:
    - x86: CMPXCHG
    - 단일 명령 (원자적)
    - 락 없이 보장

  JVM 이 native 로 사용

1.6 ILIC 의 맥락

@Service
public class CASBasics {
    
    private final AtomicInteger processedCount = new AtomicInteger(0);
    
    // CAS 기반 증가
    public void process(Shipment shipment) {
        doProcess(shipment);
        processedCount.incrementAndGet();   // CAS (락 없이 원자적)
    }
    
    // compareAndSet 직접 사용
    private final AtomicReference<Status> status = 
        new AtomicReference<>(Status.IDLE);
    
    public boolean startProcessing() {
        // IDLE → PROCESSING (CAS)
        return status.compareAndSet(Status.IDLE, Status.PROCESSING);
        // IDLE 이면 PROCESSING 으로 (성공)
        // 아니면 false (이미 처리 중)
    }
    
    enum Status { IDLE, PROCESSING, DONE }
    private void doProcess(Shipment s) { }
}

1.7 자기 점검 답변

CAS 알고리즘 4단계는?

:
1. 4단계:

  • 현재 값 읽기 (A)
  • 새 값 계산 (B)
  • 메모리 == A 비교
  • 같으면 교체, 다르면 재시도
  1. compareAndSet:

    • 비교 + 교체
  2. 하드웨어:

    • CPU 명령 (CMPXCHG)
  3. 원자적:

    • 단일 명령

2️⃣ 락 없이 원자성 (논블로킹)

2.1 논블로킹

논블로킹 (Non-blocking):

  락 없이 원자성:
    - CAS 로 시도
    - 실패 시 재시도
    - 대기 (BLOCKED) X

2.2 블로킹 vs 논블로킹

블로킹 vs 논블로킹:

synchronized (블로킹):
  - 락 획득
  - 다른 스레드 BLOCKED
  - 대기

CAS (논블로킹):
  - 락 없이 시도
  - 실패 시 재시도
  - 대기 X (계속 진행)

2.3 낙관적 vs 비관적

낙관적 vs 비관적:

synchronized (비관적):
  - "충돌할 거야" 가정
  - 미리 락

CAS (낙관적):
  - "충돌 안 할 거야" 가정
  - 일단 시도
  - 충돌 시만 재시도

2.4 장점

논블로킹 장점:

  - 대기 없음 (BLOCKED X)
  - 데드락 없음 (락 X)
  - 컨텍스트 스위칭 적음
  - 경쟁 낮으면 빠름

2.5 단점

논블로킹 단점:

  - 경쟁 높으면 재시도 ↑
  - CPU 사용 (재시도 루프)
  - 복잡한 연산 어려움 (단일 변수)
  - ABA 문제

2.6 ILIC 의 맥락

@Service
public class NonBlockingAtomicity {
    
    // 논블로킹 카운터
    private final AtomicLong totalProcessed = new AtomicLong();
    
    public void process(Shipment shipment) {
        doProcess(shipment);
        totalProcessed.incrementAndGet();   // 논블로킹
        // 락 없이, 대기 없이 (CAS)
    }
    
    // 논블로킹 상태 전이
    private final AtomicReference<ProcessState> state = 
        new AtomicReference<>(ProcessState.READY);
    
    public boolean tryStart() {
        // CAS 로 상태 전이 (락 없이)
        return state.compareAndSet(ProcessState.READY, ProcessState.RUNNING);
        // 성공: 시작, 실패: 이미 실행 중 (대기 X)
    }
    
    enum ProcessState { READY, RUNNING, DONE }
    private void doProcess(Shipment s) { }
}

2.7 자기 점검 답변

Atomic이 락 없이 원자성을 보장하는 원리는?

:
1. 논블로킹:

  • 락 없이 CAS
  • 대기 X
  1. vs 블로킹:

    • synchronized: BLOCKED
    • CAS: 재시도
  2. 낙관적:

    • 일단 시도
  3. 장점:

    • 데드락 X, 스위칭 ↓

3️⃣ 재시도 동작

3.1 재시도

재시도 (retry):

  CAS 실패 시:
    - 다른 스레드가 이미 수정
    - 새 값 다시 읽기
    - 다시 계산
    - 다시 CAS

3.2 재시도 루프

// 재시도 루프 (스핀)
do {
    current = get();           // 다시 읽기
    next = compute(current);   // 다시 계산
} while (!compareAndSet(current, next));   // 성공까지 재시도

3.3 언제 실패

CAS 실패 (재시도):

  현재 값 != 기대값:
    - 다른 스레드가 수정
    - 기대값 안 맞음
    - 재시도

  → 충돌 시 재시도

3.4 무한 반복?

무한 반복 가능성:

  이론적:
    - 계속 충돌하면 무한 재시도

  실제:
    - 결국 성공 (확률적)
    - 경쟁 높아도 진전
    - lock-free 보장 (누군가 성공)

  → 라이브락 가능성 (드묾)

3.5 경쟁과 재시도

경쟁과 재시도:

경쟁 낮음:
  - 재시도 거의 X
  - 빠름

경쟁 높음:
  - 재시도 ↑
  - CPU 사용 ↑
  - synchronized 가 나을 수도

3.6 ILIC 의 맥락

@Service
public class RetryBehavior {
    
    private final AtomicReference<BigDecimal> totalFreight = 
        new AtomicReference<>(BigDecimal.ZERO);
    
    // CAS 재시도 (누적)
    public void addFreight(BigDecimal amount) {
        BigDecimal current, next;
        do {
            current = totalFreight.get();      // 현재 (다시 읽기)
            next = current.add(amount);         // 계산 (다시)
        } while (!totalFreight.compareAndSet(current, next));   // 재시도
        // 다른 스레드가 끼어들면 재시도
    }
    
    // updateAndGet (재시도 내장)
    public BigDecimal addFreightSimple(BigDecimal amount) {
        return totalFreight.updateAndGet(current -> current.add(amount));
        // 내부적으로 CAS 재시도
    }
}

3.7 자기 점검 답변

CAS의 "재시도" 동작은?

:
1. 재시도:

  • CAS 실패 시
  • 다시 읽기/계산/CAS
  1. 루프:

    • 성공까지 스핀
  2. 언제 실패:

    • 현재 != 기대값
  3. 무한?:

    • 이론적 가능
    • 실제 결국 성공

4️⃣ 은행 잔액 예시

4.1 시나리오

은행 잔액 예시:

초기 잔액: 100

스레드1: +50 (100 → 150)
스레드2: +50 (100 → 150) 동시

4.2 CAS 흐름

CAS 흐름:

스레드1:
  1. 100 읽음 (기대값 100)
  2. 100 + 50 = 150 계산
  3. 메모리 100 == 100? YES
  4. 150 으로 교체 (성공)
  잔액: 150

스레드2 (스레드1 직후):
  1. 100 읽음 (기대값 100)
  2. 100 + 50 = 150 계산
  3. 메모리 150 == 100? NO (변함!)
  4. 재시도
     1'. 150 읽음 (기대값 150)
     2'. 150 + 50 = 200
     3'. 메모리 150 == 150? YES
     4'. 200 으로 교체 (성공)
  잔액: 200 ✓

4.3 손실 없음

손실 없음:

  최종 잔액: 200 (100 + 50 + 50)
    - 스레드1: 150
    - 스레드2: 재시도 → 200

  CAS 가 손실 방지:
    - 충돌 감지 (비교)
    - 재시도 (최신 값)

4.4 코드

@Service
public class BankBalanceExample {
    
    private final AtomicReference<BigDecimal> balance = 
        new AtomicReference<>(BigDecimal.valueOf(100));
    
    // CAS 입금
    public void deposit(BigDecimal amount) {
        BigDecimal current, next;
        do {
            current = balance.get();        // 현재 잔액
            next = current.add(amount);     // 새 잔액
        } while (!balance.compareAndSet(current, next));   // CAS
        // 충돌 시 재시도 → 손실 없음
    }
    
    // 두 스레드가 동시 +50 해도
    // 최종 200 (손실 X)
}

4.5 synchronized 비교

// synchronized 버전 (블로킹)
private BigDecimal balance = BigDecimal.valueOf(100);

public synchronized void deposit(BigDecimal amount) {
    balance = balance.add(amount);   // 락 (한 스레드씩)
}
// CAS: 논블로킹 (재시도)
// synchronized: 블로킹 (대기)
// 결과 동일, 방식 다름

4.6 ILIC 의 맥락

@Service
public class FreightBalanceCAS {
    
    // 운임 정산 잔액 (CAS)
    private final AtomicReference<BigDecimal> accountBalance = 
        new AtomicReference<>(BigDecimal.ZERO);
    
    // 운임 청구 (차감)
    public boolean charge(BigDecimal freight) {
        BigDecimal current, next;
        do {
            current = accountBalance.get();
            if (current.compareTo(freight) < 0) {
                return false;   // 잔액 부족
            }
            next = current.subtract(freight);
        } while (!accountBalance.compareAndSet(current, next));
        return true;
        // 동시 청구해도 정확 (CAS 재시도)
    }
    
    // 충전 (가산)
    public void recharge(BigDecimal amount) {
        accountBalance.updateAndGet(current -> current.add(amount));
    }
}

4.7 자기 점검 답변

은행 잔액 예시로 CAS 흐름은?

:
1. 시나리오:

  • 100, 동시 +50 두 스레드
  1. 스레드1:

    • 100 일치 → 150 성공
  2. 스레드2:

    • 150 ≠ 100 → 재시도
    • 150 → 200 성공
  3. 결과:

    • 200 (손실 없음)

5️⃣ 3종 비교 매트릭스

5.1 비교 매트릭스

도구가시성원자성방식성능
synchronized락 (블로킹)가장 느림
volatile메모리 동기화빠름
AtomicCAS (논블로킹)빠름

5.2 가시성

가시성 (셋 다 ✅):

  synchronized: 락 동기화
  volatile: 메인 메모리 직접
  Atomic: 내부 volatile + CAS

  → 모두 가시성 보장

5.3 원자성

원자성:

  synchronized: ✅ (락)
  volatile: ❌ (복합 X)
  Atomic: ✅ (CAS)

  → volatile 만 원자성 X

5.4 방식

방식:

  synchronized: 블로킹 (락, 대기)
  volatile: 메모리 동기화 (가시성만)
  Atomic: 논블로킹 (CAS, 재시도)

5.5 선택 가이드

선택 가이드:

가시성만 (플래그):
  → volatile

단일 변수 원자 연산:
  → Atomic (빠름)

복잡한 복합 (여러 변수):
  → synchronized

→ 용도별

5.6 ILIC 의 맥락

@Service
public class ThreeToolsComparison {
    
    // volatile — 가시성만 (플래그)
    private volatile boolean running = true;
    public void stop() { running = false; }
    
    // Atomic — 단일 변수 원자 (카운터)
    private final AtomicInteger count = new AtomicInteger();
    public void increment() { count.incrementAndGet(); }
    
    // synchronized — 복잡한 복합 (여러 변수 일관성)
    private int total = 0;
    private final Map<Long, Shipment> shipments = new HashMap<>();
    public synchronized void addShipment(Shipment s) {
        shipments.put(s.getId(), s);
        total++;
        // 두 상태 일관성 → synchronized
    }
    
    // 각 도구를 용도에 맞게
}

5.7 자기 점검 답변

3종 비교 매트릭스는?

:
1. 가시성:

  • 셋 다 ✅
  1. 원자성:

    • synchronized ✅, volatile ❌, Atomic ✅
  2. 방식:

    • 락 / 메모리 / CAS
  3. 선택:

    • 플래그: volatile
    • 카운터: Atomic
    • 복합: synchronized

6️⃣ ABA 문제

6.1 ABA 문제

ABA 문제:

  값이 A → B → A 로 변하면:
    - CAS 는 A 그대로 봄
    - 변하지 않은 것으로 오인
    - 사실은 변했는데

6.2 시나리오

ABA 시나리오:

스레드1: A 읽음 (기대값 A)
    ↓ (스레드1 잠시 멈춤)
스레드2: A → B 변경
스레드3: B → A 변경 (다시 A)
    ↓
스레드1: CAS (A == A? YES) → 성공
    - 하지만 중간에 B 거쳐감
    - 스레드1 은 모름

6.3 왜 문제

왜 문제:

  단순 값:
    - ABA 무해 (값만 같으면 OK)

  참조/구조:
    - 중간 변화 중요
    - 예: 스택 pop/push
    - 노드 재사용 시 오류

6.4 해결 — 버전 태그

// AtomicStampedReference (버전 태그)
AtomicStampedReference<String> ref = 
    new AtomicStampedReference<>("A", 0);   // 값 + 스탬프(버전)

int[] stampHolder = new int[1];
String value = ref.get(stampHolder);   // 값 + 스탬프 읽기
int stamp = stampHolder[0];

// CAS with 스탬프
ref.compareAndSet("A", "B", stamp, stamp + 1);
// 값 + 스탬프 모두 일치해야 성공
// A → B → A 면 스탬프 다름 → 감지

6.5 AtomicMarkableReference

ABA 해결 클래스:

AtomicStampedReference:
  - 값 + int 스탬프 (버전)
  - 버전으로 변화 감지

AtomicMarkableReference:
  - 값 + boolean 마크
  - 표시 여부

6.6 ILIC 의 맥락

@Service
public class ABAProblem {
    
    // 일반 AtomicReference (ABA 가능)
    private final AtomicReference<Node> head = new AtomicReference<>();
    
    // ABA 방지 — 버전 태그
    private final AtomicStampedReference<ShipmentState> state = 
        new AtomicStampedReference<>(new ShipmentState("READY"), 0);
    
    public boolean transition(ShipmentState expected, ShipmentState next) {
        int[] stampHolder = new int[1];
        ShipmentState current = state.get(stampHolder);
        int currentStamp = stampHolder[0];
        
        // 값 + 버전 모두 확인 (ABA 방지)
        return state.compareAndSet(
            current, next, 
            currentStamp, currentStamp + 1);
        // READY → PROCESSING → READY 거쳐도
        // 버전 다름 → 감지
    }
    
    record ShipmentState(String name) {}
    record Node(int value) {}
}

6.7 자기 점검 답변

ABA 문제란?

:
1. ABA:

  • A → B → A
  • 변화 못 감지
  1. 시나리오:

    • 중간에 B 거침
    • CAS 는 A 그대로 봄
  2. 문제:

    • 참조/구조에서 위험
  3. 해결:

    • AtomicStampedReference (버전)

7️⃣ Atomic이 빠른 이유

7.1 빠른 이유

Atomic 이 synchronized 보다 빠른 이유:

  1. 락 없음 (논블로킹)
  2. BLOCKED 없음
  3. 컨텍스트 스위칭 적음
  4. 단일 CPU 명령 (CAS)

7.2 락 오버헤드 없음

락 오버헤드 없음:

synchronized:
  - 락 획득/해제
  - 경쟁 시 BLOCKED
  - 스위칭

Atomic:
  - 락 없음
  - CAS 명령 (가벼움)
  - 스위칭 적음

7.3 경쟁 낮을 때

경쟁 낮을 때:

  Atomic:
    - CAS 한 번에 성공
    - 매우 빠름

  synchronized:
    - 락 획득/해제 비용
    - 상대적 느림

→ 경쟁 낮으면 Atomic 압승

7.4 경쟁 높을 때

경쟁 높을 때:

  Atomic:
    - 재시도 ↑
    - CPU 사용 (스핀)

  synchronized:
    - 큐 대기 (CPU 양보)

→ 경쟁 매우 높으면
→ synchronized 가 나을 수도
→ 또는 LongAdder

7.5 LongAdder

// 경쟁 높을 때 — LongAdder
LongAdder adder = new LongAdder();
adder.increment();   // 분산 (cell 별)
long sum = adder.sum();

// AtomicLong: 단일 변수 (경쟁 ↑ 재시도)
// LongAdder: 분산 (경쟁 분산, 빠름)
// 카운터 경쟁 높으면 LongAdder

7.6 ILIC 의 맥락

@Service
public class WhyAtomicFaster {
    
    // 경쟁 낮음 — AtomicInteger
    private final AtomicInteger lowContention = new AtomicInteger();
    
    public void occasionalUpdate() {
        lowContention.incrementAndGet();   // 빠름 (CAS 한 번)
    }
    
    // 경쟁 높음 — LongAdder
    private final LongAdder highContention = new LongAdder();
    
    public void frequentUpdate() {
        highContention.increment();   // 분산 (경쟁 ↓)
    }
    
    public long getTotal() {
        return highContention.sum();   // 집계
    }
    
    // 카운터 경쟁:
    // 낮음 → AtomicInteger/Long
    // 높음 → LongAdder
}

7.7 자기 점검 답변

Atomic이 synchronized보다 빠른 이유는?

:
1. 빠른 이유:

  • 락 없음 (논블로킹)
  • BLOCKED 없음
  1. 경쟁 낮을 때:

    • CAS 한 번 성공
    • 압승
  2. 경쟁 높을 때:

    • 재시도 ↑
    • LongAdder 고려
  3. 단일 명령:

    • CAS (CPU)

8️⃣ 주요 Atomic 클래스

8.1 기본 Atomic

기본 Atomic:

  AtomicInteger: int
  AtomicLong: long
  AtomicBoolean: boolean
  AtomicReference<V>: 참조

8.2 주요 메서드

AtomicInteger ai = new AtomicInteger(0);

ai.get();                        // 읽기
ai.set(5);                       // 쓰기
ai.incrementAndGet();            // ++x (원자적)
ai.getAndIncrement();            // x++ (원자적)
ai.addAndGet(10);                // += 10
ai.compareAndSet(5, 10);         // CAS
ai.updateAndGet(x -> x * 2);     // 함수 적용 (CAS 재시도)
ai.accumulateAndGet(5, Integer::sum);   // 누적

8.3 배열 Atomic

배열 Atomic:

  AtomicIntegerArray
  AtomicLongArray
  AtomicReferenceArray

  - 배열 요소별 원자 연산
  - volatile 배열과 다름

8.4 고성능 (Java 8+)

고성능 누산기 (Java 8+):

  LongAdder: 분산 long 누적
  LongAccumulator: 커스텀 누적
  DoubleAdder, DoubleAccumulator

  - 경쟁 높을 때
  - 분산 (cell)

8.5 필드 업데이터

// AtomicReferenceFieldUpdater (필드 원자 갱신)
class Node {
    volatile Node next;
    static final AtomicReferenceFieldUpdater<Node, Node> NEXT =
        AtomicReferenceFieldUpdater.newUpdater(
            Node.class, Node.class, "next");
}
// 객체 필드를 원자적으로 (메모리 절약)

8.6 ILIC 의 맥락

@Service
public class AtomicClasses {
    
    // AtomicInteger — 카운터
    private final AtomicInteger processedCount = new AtomicInteger();
    
    // AtomicLong — 누적
    private final AtomicLong totalBytes = new AtomicLong();
    
    // AtomicReference — 상태
    private final AtomicReference<Config> config = 
        new AtomicReference<>(new Config());
    
    // AtomicBoolean — 플래그 (CAS 가능)
    private final AtomicBoolean initialized = new AtomicBoolean(false);
    
    // LongAdder — 고경쟁 카운터
    private final LongAdder requestCount = new LongAdder();
    
    public void process(Shipment shipment) {
        processedCount.incrementAndGet();
        totalBytes.addAndGet(shipment.getSize());
        requestCount.increment();   // 고경쟁
    }
    
    public boolean initOnce() {
        // 한 번만 초기화 (CAS)
        return initialized.compareAndSet(false, true);
    }
    
    record Config() {}
}

8.7 자기 점검 답변

주요 Atomic 클래스는?

:
1. 기본:

  • AtomicInteger/Long
  • AtomicBoolean/Reference
  1. 메서드:

    • incrementAndGet
    • compareAndSet
    • updateAndGet
  2. 배열:

    • AtomicIntegerArray 등
  3. 고성능:

    • LongAdder (경쟁 ↑)

9️⃣ 면접 + 자기 점검 + 마스터 50문항

9.1 면접 단골 질문 매핑

Q핵심 답변
CAS 4단계?읽기/계산/비교/교체or재시도
논블로킹?락 없이 재시도
재시도?충돌 시 다시
은행 예시?100→150→200 (재시도)
3종 비교?sync(락)/volatile(가시성)/Atomic(CAS)
ABA?A→B→A 못 감지
ABA 해결?AtomicStampedReference
Atomic 빠른 이유?락 없음
무한 재시도?이론적, 실제 성공
LongAdder?고경쟁 분산

9.2 마스터 자기 점검 체크리스트

CAS

  • 4단계
  • compareAndSet

논블로킹

  • 락 없음
  • 낙관적

재시도

  • 동작
  • 무한 가능성

은행 예시

  • 흐름

3종 비교

  • 매트릭스

ABA

  • 문제
  • 해결

빠른 이유

  • 락 없음

Atomic 클래스

  • 주요 클래스

9.3 Atomic + CAS 마스터 50문항

CAS 알고리즘 (13문항)

Q1. CAS? → Compare And Swap
Q2. 4단계? → 읽기/계산/비교/교체or재시도
Q3. 1단계? → 현재 값 읽기 (A)
Q4. 2단계? → 새 값 계산 (B)
Q5. 3단계? → 메모리 == A 비교
Q6. 4단계? → 같으면 교체, 다르면 재시도
Q7. compareAndSet? → 비교+교체
Q8. 하드웨어? → CPU 명령 (CMPXCHG)
Q9. 원자적? → 단일 명령
Q10. 기대값? → 읽은 현재 값 (A)
Q11. 교체 성공? → 현재 == 기대값
Q12. 교체 실패? → 다름 (재시도)
Q13. 단일 변수? → CAS 적합

논블로킹/재시도 (12문항)

Q14. 논블로킹? → 락 없이
Q15. vs 블로킹? → BLOCKED 없음
Q16. 낙관적? → 일단 시도
Q17. 비관적? → synchronized (미리 락)
Q18. 재시도? → 충돌 시 다시
Q19. 재시도 루프? → 성공까지 스핀
Q20. 무한 반복? → 이론적, 실제 성공
Q21. 라이브락? → 계속 충돌 (드묾)
Q22. 데드락? → CAS 는 없음 (락 X)
Q23. 경쟁 낮음? → 재시도 적음
Q24. 경쟁 높음? → 재시도 ↑
Q25. 논블로킹 장점? → 대기/데드락 없음

3종 비교/은행 (13문항)

Q26. synchronized 가시성? → ✅
Q27. synchronized 원자성? → ✅
Q28. synchronized 방식? → 락 (블로킹)
Q29. volatile 가시성? → ✅
Q30. volatile 원자성? → ❌
Q31. volatile 방식? → 메모리 동기화
Q32. Atomic 가시성? → ✅
Q33. Atomic 원자성? → ✅
Q34. Atomic 방식? → CAS (논블로킹)
Q35. 가장 느림? → synchronized
Q36. 은행 스레드1? → 100→150 성공
Q37. 은행 스레드2? → 150≠100 재시도→200
Q38. 손실? → 없음 (CAS 재시도)

ABA/클래스 (12문항)

Q39. ABA? → A→B→A 못 감지
Q40. ABA 시나리오? → 중간 B 거침
Q41. ABA 문제? → 참조/구조
Q42. ABA 해결? → AtomicStampedReference
Q43. 스탬프? → 버전 태그
Q44. AtomicInteger? → int 원자
Q45. AtomicReference? → 참조 원자
Q46. incrementAndGet? → ++x
Q47. updateAndGet? → 함수 (CAS 재시도)
Q48. LongAdder? → 고경쟁 분산
Q49. Atomic 빠른 이유? → 락 없음
Q50. 단일 명령? → CAS (CPU)

9.4 채점

50 / 50 → Atomic + CAS 마스터
45-49   → 거의 마스터
40-44   → 복습
< 40    → Unit 2.4 재학습

9.5 추가 심화 질문

Q1: CAS 의 재시도가 무한 반복될 수 있는가?

답:

  • 이론적: 계속 충돌하면 무한 (라이브락)
  • 실제: 누군가는 성공 (lock-free 보장)
  • 확률적으로 결국 성공
  • 경쟁 극심하면 LongAdder/synchronized

Q2: Unsafe 와 CAS?

답:

  • sun.misc.Unsafe.compareAndSwapInt
  • Atomic 내부에서 사용
  • native CAS 호출
  • Java 9+ VarHandle 권장

Q3: VarHandle?

답:

  • Java 9+ Unsafe 대체
  • compareAndSet 등
  • 필드/배열 원자 연산
  • 안전한 저수준 API

Q4: LongAdder vs AtomicLong?

답:

  • AtomicLong: 단일 변수 (경쟁 시 재시도)
  • LongAdder: 분산 cell (경쟁 분산)
  • 쓰기 많으면 LongAdder
  • 읽기 정확성 필요하면 AtomicLong

Q5: CAS 와 메모리 가시성?

답:

  • CAS 자체가 volatile 연산
  • 가시성 보장
  • Atomic 내부 value 가 volatile
  • CAS + volatile = 가시성 + 원자성

🎯 핵심 요약 — 3줄 정리

1. CAS 4단계

  • 읽기(A) → 계산(B) → 비교(메모리==A) → 교체or재시도
  • 락 없이 원자성 (논블로킹, 낙관적)

2. 3종 비교

  • synchronized: 락 (둘 다, 느림)
  • volatile: 메모리 (가시성만)
  • Atomic: CAS (둘 다, 빠름)

3. 주의

  • ABA 문제 (A→B→A) → AtomicStampedReference
  • 경쟁 높으면 재시도 ↑ → LongAdder

🏆 Phase 2 완주 — 동시성 안전 도구 마스터

🚀 Phase 2 — 동시성 안전 도구 3종 비교
  ✅ Unit 2.1 두 가지 동시성 문제 구분
  ✅ Unit 2.2 synchronized
  ✅ Unit 2.3 volatile
  ✅ Unit 2.4 Atomic + CAS (★ 마스터) ← 여기, Phase 2 완주

→ 가시성 vs 원자성
→ synchronized / volatile / Atomic
→ CAS 알고리즘

🎓 Part A (동시성 마무리) 완주

✅ Part A — 동시성 마무리
  ✅ Phase 1 — 스레드 풀의 필요성 (3 Unit)
  ✅ Phase 2 — 동시성 안전 도구 3종 (4 Unit)

→ 4주차 동시성 + 5주차 Atomic/CAS
→ 자바 동시성 완성
→ 이제 Spring 으로 (Part B)

📚 다음으로...

Part B 시작 — Phase 3 — 전통 DAO의 문제

이제 토비의 스프링: 객체 설계의 진화 로 진입합니다.

Part B — 토비의 스프링
  Phase 3 — 전통 DAO의 문제
    Unit 3.1 — DAO란 무엇인가
    Unit 3.2 — 전통 DAO의 코드
    Unit 3.3 — 책임 혼재

5주차 누적 진행

✅ Part A — 동시성 마무리 (7 Unit) ← 완주
  ✅ Phase 1 (3) + Phase 2 (4, 2.4 ★마스터)
⏭ Part B — 토비의 스프링 (Phase 3~8, 19 Unit)

총: 7/26 Unit

★ 마스터 Unit — Atomic + CAS 완료
🏆 Phase 2 완주 + 🎓 Part A (동시성 마무리) 완주

profile
Software Developer

0개의 댓글