5주차 Unit 2.3 — volatile: 가시성만, 원자성은 ❌

Psj·2026년 5월 26일

F-lab

목록 보기
161/240

Unit 2.3 — volatile: 가시성만, 원자성은 ❌

F-LAB JAVA · 5주차 · Phase 2 · 동시성 안전 도구 3종 비교


📌 학습 목표

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

  • volatile 이 가시성을 보장 하는 원리는?
  • volatile 이 원자성을 보장하지 못하는 이유는?
  • count++ 가 volatile 로도 안전하지 않은 이유 (바이트코드 수준) 는?
  • volatile 의 적합한 사용처 (플래그) 는?
  • volatile 이 적합한 시나리오 3가지 는?
  • volatile 과 메모리 배리어 의 관계는?
  • volatile 과 순서 (ordering) 보장 은?
  • DCL (Double-Checked Locking) 과 volatile 은?
  • volatile 의 한계 는?

🎯 핵심 한 문장

volatile 은 변수를 메인 메모리에서 직접 읽고 쓰게 하여 가시성을 보장하지만, 복합 연산 (read-modify-write) 의 원자성은 보장하지 못하므로, "한 스레드만 쓰고 여러 스레드가 읽는 플래그" 에 적합하다.
가시성 보장 — volatile 변수는 CPU 캐시를 거치지 않고 메인 메모리에 직접 읽고 쓰므로, 한 스레드의 변경이 다른 스레드에 즉시 보인다.
원자성 미보장count++ 는 읽기-증가-쓰기의 3단계 복합 연산인데, volatile 은 각 단계의 가시성만 보장할 뿐 세 단계를 하나로 묶지 못하므로 여전히 갱신 손실이 발생한다.
바이트코드 수준에서 count++getfield → iconst_1 → iadd → putfield 로 분리되며, 이 사이에 다른 스레드가 끼어들 수 있어 volatile 로도 막을 수 없다.
따라서 volatile 은 단일 쓰기 + 다중 읽기 플래그 (예: shutdown, running), 상태 발행 (한 번 쓰고 읽기), 이중 검사 락의 인스턴스 참조 같은 시나리오에 적합하다.

비유 — 실시간 전광판

volatile = 실시간 전광판:

가시성 (즉시 반영):
  - 전광판에 직접 표시 (메인 메모리)
  - 모두가 즉시 봄
  - 자기 수첩(캐시) 안 봄

  vs 일반 변수:
    - 각자 수첩에 적음 (캐시)
    - 갱신 안 보일 수 있음

원자성 X (복합 연산):
  - "관람객 수 +1" 을 두 명이 동시에
  - A: 전광판 100 읽음 → 101 표시 준비
  - B: 전광판 100 읽음 (동시) → 101 표시 준비
  - 둘 다 101 표시 (102 여야 하는데)
  → 전광판이라도 "읽고+1하고쓰기" 는 안 묶임

적합한 용도:
  - 단순 상태 표시 (영업중/마감)
  - 한 명만 바꾸고 (점장)
  - 여러 명이 봄 (손님)
  → 플래그

→ volatile = 메인 메모리 직접 (가시성), 복합 연산 원자성 X, 플래그에 적합.


🧭 9개 섹션 로드맵

1. 가시성 보장 원리
2. 원자성 미보장
3. count++ 분석 (바이트코드)
4. 적합한 사용처 (플래그)
5. 적합한 시나리오 3가지
6. 메모리 배리어
7. 순서 보장
8. DCL과 volatile
9. 면접 + 자기 점검

1️⃣ 가시성 보장 원리

1.1 메인 메모리 직접

volatile 가시성:

  메인 메모리에서 직접 R/W:
    - CPU 캐시 우회
    - 쓰기: 즉시 메인 메모리
    - 읽기: 메인 메모리에서

  → 변경 즉시 보임

1.2 캐시 우회

캐시 우회:

일반 변수:
  - 캐시에 저장 (성능)
  - 변경이 캐시에만
  - 다른 코어 못 봄

volatile:
  - 메인 메모리 직접
  - 모든 코어 최신

1.3 예시

// volatile 가시성
private volatile boolean running = true;

// 스레드 1
while (running) {   // 메인 메모리에서 읽기 (최신)
    work();
}

// 스레드 2
running = false;   // 메인 메모리에 쓰기 (즉시 보임)
// 스레드 1 이 즉시 봄 → 루프 종료

1.4 가시성만

volatile = 가시성만:

  ✅ 가시성
  ❌ 원자성

  단일 읽기/쓰기는 원자적:
    - 읽기 1회, 쓰기 1회
  복합 연산은 X:
    - count++ (3단계)

1.5 ILIC 의 맥락

@Service
public class VolatileVisibility {
    
    // volatile — 가시성 보장
    private volatile boolean shutdownRequested = false;
    
    public void worker() {
        while (!shutdownRequested) {   // 메인 메모리 (최신)
            processNext();
        }
        log.info("Worker stopped");
    }
    
    public void requestShutdown() {
        shutdownRequested = true;   // 즉시 보임
        // worker 가 다음 확인 시 종료
    }
    
    private void processNext() { }
}

1.6 자기 점검 답변

volatile이 가시성을 보장하는 원리는?

:
1. 메인 메모리 직접:

  • 캐시 우회
  • 즉시 R/W
  1. 캐시 우회:

    • 모든 코어 최신
  2. 예시:

    • 플래그 즉시 보임
  3. 가시성만:

    • 원자성 X

2️⃣ 원자성 미보장

2.1 원자성 X

volatile 원자성 미보장:

  복합 연산 (RMW):
    - count++
    - 각 단계 가시성만
    - 묶지 못함 (원자성 X)

→ 손실 가능

2.2 왜 안 되나

왜 원자성 X:

  volatile 은:
    - 각 읽기/쓰기 가시성
    - 하지만 "읽고+1하고쓰기" 를
    - 하나로 묶지 X

  중간에 다른 스레드 개입 가능

2.3 count++ 손실

// volatile 로도 손실
private volatile int count = 0;

count++;
// 1. count 읽기 (가시성 O)
// 2. +1
// 3. count 쓰기 (가시성 O)
// 1~3 사이 다른 스레드 개입 가능
// → 손실

2.4 시각화

volatile count++ 손실:

스레드 A    스레드 B    count(메인)
읽기(5)                  5
            읽기(5)      5  ← 둘 다 5 (가시성 OK여도)
+1 (6)
            +1 (6)
쓰기(6)                  6
            쓰기(6)      6  ← 손실

  가시성은 OK (둘 다 5 정확히 읽음)
  하지만 원자성 X (손실)

2.5 단일 연산은 OK

// 단일 읽기/쓰기는 원자적 (volatile)
private volatile boolean flag;
private volatile int value;

flag = true;        // 단일 쓰기 (원자적 + 가시성)
boolean f = flag;   // 단일 읽기 (원자적 + 가시성)
value = 10;         // 단일 쓰기 OK

// 복합만 문제
value++;            // 복합 (원자성 X)

2.6 ILIC 의 맥락

@Service
public class VolatileNoAtomicity {
    
    // ❌ volatile count++ (손실)
    private volatile int processedCount = 0;
    
    public void processWrong(Shipment shipment) {
        doProcess(shipment);
        processedCount++;   // 가시성 O, 원자성 X → 손실
    }
    
    // ✓ 단일 쓰기는 OK
    private volatile long lastProcessedTime;
    
    public void updateTime() {
        lastProcessedTime = System.currentTimeMillis();   // 단일 쓰기 OK
    }
    
    // ✓ 카운터는 AtomicInteger
    private final AtomicInteger correctCount = new AtomicInteger();
    
    public void processCorrect(Shipment shipment) {
        doProcess(shipment);
        correctCount.incrementAndGet();   // 원자적
    }
    
    private void doProcess(Shipment s) { }
}

2.7 자기 점검 답변

volatile이 원자성을 보장하지 못하는 이유는?

:
1. 원자성 X:

  • 복합 연산 (RMW)
  • 묶지 못함
  1. 이유:

    • 각 단계 가시성만
    • 중간 개입
  2. count++ 손실:

    • 가시성 OK여도 손실
  3. 단일 OK:

    • 단일 읽기/쓰기는 원자적

3️⃣ count++ 분석 (바이트코드)

3.1 바이트코드 분해

// count++ 의 바이트코드
count++;

// 바이트코드:
// getfield      // count 읽기 (스택에 push)
// iconst_1      // 1 push
// iadd          // 더하기
// putfield      // count 쓰기

// → 4개 명령 (분리)

3.2 3단계 (개념)

count++ 3단계:

1. read: count 값 읽기
2. modify: +1 계산
3. write: count 에 쓰기

  volatile:
    - 1, 3 의 가시성
    - 하지만 1~3 사이 개입 가능

3.3 인터리빙

인터리빙 (interleaving):

스레드 A: getfield (5)
스레드 B: getfield (5)  ← A 와 B 사이
스레드 A: iadd (6)
스레드 A: putfield (6)
스레드 B: iadd (6)
스레드 B: putfield (6)  ← 덮어씀

  명령 사이 끼어듦
  → 손실

3.4 원자적이려면

원자적이려면:

  getfield ~ putfield 를
  하나로 묶어야:
    - synchronized (락)
    - Atomic (CAS)

  volatile 은 각 명령 가시성만
  → 묶지 못함

3.5 다른 복합 연산

// 모든 복합 연산 위험 (volatile)
volatile int v;

v++;              // read-modify-write
v += 5;           // read-modify-write
v = v * 2;        // read-modify-write
if (v == 0) v = 1;   // check-then-act

// 모두 원자성 X (volatile 부족)

3.6 ILIC 의 맥락

@Service
public class CountIncrementAnalysis {
    
    private volatile int counter = 0;
    
    // 바이트코드 수준 위험
    public void increment() {
        counter++;
        // getfield counter
        // iconst_1
        // iadd
        // putfield counter
        // → 4명령 분리, 인터리빙 가능
    }
    
    // 올바른 방법
    private final AtomicInteger atomicCounter = new AtomicInteger();
    
    public void incrementCorrect() {
        atomicCounter.incrementAndGet();
        // CAS 로 원자적 (단일 연산처럼)
    }
    
    // 측정: increment() 를 여러 스레드로 호출하면
    // 최종 값 < 기대값 (손실 확인)
}

3.7 자기 점검 답변

count++가 volatile로도 안전하지 않은 이유는?

:
1. 바이트코드:

  • getfield/iadd/putfield
  • 4명령 분리
  1. 3단계:

    • read-modify-write
  2. 인터리빙:

    • 명령 사이 개입
  3. 원자적이려면:

    • synchronized/Atomic
    • volatile 부족

4️⃣ 적합한 사용처 (플래그)

4.1 플래그

volatile 적합 — 플래그:

  한 스레드만 쓰고
  여러 스레드가 읽는 boolean:
    - 단일 쓰기 (원자성 OK)
    - 가시성 필요 (volatile)

4.2 shutdown 플래그

// shutdown 플래그 (대표)
private volatile boolean shutdown = false;

// 한 곳에서만 쓰기
public void stop() {
    shutdown = true;   // 단일 쓰기
}

// 여러 스레드 읽기
public void worker() {
    while (!shutdown) {   // 가시성 (즉시 종료)
        work();
    }
}

4.3 왜 적합

왜 플래그에 적합:

  - 단일 쓰기 (원자성 문제 없음)
  - 여러 읽기 (가시성 필요)
  - 복합 연산 아님

  → volatile 로 충분
  → synchronized 불필요 (가벼움)

4.4 조건 — 단일 쓰기

조건 — 단일 쓰기:

  volatile 안전 조건:
    - 쓰기가 다른 값에 의존 X
    - 단순 대입 (= true)
    - count++ 같은 RMW X

  → 단일 쓰기만 안전

4.5 ILIC 의 맥락

@Service
public class VolatileFlagUsage {
    
    // 적합한 플래그들 (단일 쓰기, 여러 읽기)
    private volatile boolean running = true;
    private volatile boolean maintenanceMode = false;
    private volatile String currentPhase = "INIT";
    
    // 단일 쓰기 (안전)
    public void shutdown() {
        running = false;   // 한 곳에서만
    }
    
    public void enableMaintenance() {
        maintenanceMode = true;   // 단일 쓰기
    }
    
    public void setPhase(String phase) {
        currentPhase = phase;   // 단일 쓰기 (참조 대입)
    }
    
    // 여러 워커 스레드가 읽기
    public void worker() {
        while (running && !maintenanceMode) {
            processNext();
        }
    }
    
    private void processNext() { }
}

4.6 자기 점검 답변

volatile의 적합한 사용처 (플래그) 는?

:
1. 플래그:

  • 단일 쓰기, 여러 읽기
  1. shutdown:

    • 대표 사례
  2. 왜 적합:

    • 단일 쓰기 (원자성 OK)
    • 가시성 (volatile)
  3. 조건:

    • 단일 쓰기만

5️⃣ 적합한 시나리오 3가지

5.1 시나리오 1 — 상태 플래그

시나리오 1 — 상태 플래그:

  한 스레드 쓰기, 여러 읽기:
    - shutdown
    - running
    - initialized

  단일 쓰기 + 가시성

5.2 시나리오 2 — 상태 발행

// 시나리오 2 — 상태 발행 (publish)
private volatile Config config;   // 참조

// 한 번 설정 (발행)
public void publish(Config newConfig) {
    config = newConfig;   // 단일 쓰기 (참조)
}

// 여러 스레드 읽기
public Config getConfig() {
    return config;   // 가시성 (최신)
}
// 불변 객체 참조 발행에 적합

5.3 시나리오 3 — DCL 인스턴스

// 시나리오 3 — Double-Checked Locking
public class Singleton {
    private static volatile Singleton instance;   // volatile 필수
    
    public static Singleton getInstance() {
        if (instance == null) {           // 1차 (락 없이)
            synchronized (Singleton.class) {
                if (instance == null) {   // 2차 (락 안)
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
// volatile 로 재정렬 방지 (다음 섹션)

5.4 공통 조건

3 시나리오 공통:

  - 단일 쓰기 (또는 발행)
  - 복합 연산 X
  - 가시성 필요

→ volatile 적합

5.5 부적합 — 카운터

부적합 — 카운터:

  count++ 같은 복합 연산:
    - volatile X
    - Atomic / synchronized

→ RMW 는 volatile 부적합

5.6 ILIC 의 맥락

@Service
public class VolatileScenarios {
    
    // 1. 상태 플래그
    private volatile boolean systemActive = true;
    
    // 2. 상태 발행 (불변 설정)
    private volatile FreightConfig freightConfig;
    
    public void updateConfig(FreightConfig config) {
        this.freightConfig = config;   // 발행 (단일 쓰기)
    }
    
    public BigDecimal calculate(Shipment shipment) {
        FreightConfig config = this.freightConfig;   // 읽기 (최신)
        return config.calculate(shipment);
    }
    
    // 3. DCL 싱글톤 (지연 초기화)
    private static volatile FreightCalculator calculator;
    public static FreightCalculator getCalculator() {
        if (calculator == null) {
            synchronized (VolatileScenarios.class) {
                if (calculator == null) {
                    calculator = new FreightCalculator();
                }
            }
        }
        return calculator;
    }
    
    record FreightConfig() {
        BigDecimal calculate(Shipment s) { return s.getWeight(); }
    }
    static class FreightCalculator {}
}

5.7 자기 점검 답변

volatile이 적합한 시나리오 3가지는?

:
1. 상태 플래그:

  • shutdown, running
  1. 상태 발행:

    • 불변 객체 참조
  2. DCL 인스턴스:

    • 싱글톤 (재정렬 방지)
  3. 공통:

    • 단일 쓰기 + 가시성

6️⃣ 메모리 배리어

6.1 메모리 배리어

메모리 배리어 (Memory Barrier):

  CPU 명령 재정렬/캐시를 제어하는 장벽.
  - volatile 이 삽입
  - 가시성 + 순서 보장

6.2 volatile 의 배리어

volatile 배리어:

  volatile 쓰기 전후:
    - StoreStore (이전 쓰기 완료)
    - StoreLoad (메인 메모리 반영)

  volatile 읽기 전후:
    - LoadLoad
    - LoadStore

  → 재정렬 방지 + 가시성

6.3 재정렬 방지

재정렬 방지:

  컴파일러/CPU 최적화:
    - 명령 순서 바꿈 (성능)

  volatile 배리어:
    - 배리어 넘어 재정렬 X
    - 순서 보장

6.4 성능 영향

성능 영향:

  배리어:
    - 캐시 플러시
    - 재정렬 제한
    - 약간의 비용

  하지만:
    - synchronized 보다 가벼움
    - 락 없음

6.5 ILIC 의 맥락

@Service
public class MemoryBarrier {
    
    private int data = 0;            // 일반
    private volatile boolean ready = false;   // volatile (배리어)
    
    // 발행자
    public void publish(int value) {
        data = value;       // 1. 일반 쓰기
        ready = true;       // 2. volatile 쓰기 (배리어)
        // 배리어: 1 이 2 보다 먼저 (재정렬 방지)
        // → data 쓰기가 ready 전에 완료
    }
    
    // 소비자
    public int consume() {
        if (ready) {        // volatile 읽기 (배리어)
            return data;    // data 최신 (배리어로 보장)
        }
        return -1;
    }
    // volatile 이 data 가시성까지 보장 (배리어)
}

6.6 자기 점검 답변

volatile과 메모리 배리어의 관계는?

:
1. 메모리 배리어:

  • 재정렬/캐시 제어
  • volatile 삽입
  1. 배리어 종류:

    • StoreStore/StoreLoad 등
  2. 재정렬 방지:

    • 순서 보장
  3. 성능:

    • synchronized 보다 가벼움

7️⃣ 순서 보장

7.1 순서 문제

순서 (ordering) 문제:

  컴파일러/CPU 재정렬:
    - 명령 순서 변경 (최적화)
    - 단일 스레드는 문제 X
    - 멀티 스레드는 문제

7.2 volatile 순서 보장

volatile 순서 보장:

  volatile 쓰기 이전 연산:
    - volatile 쓰기보다 먼저 (재정렬 X)

  volatile 읽기 이후 연산:
    - volatile 읽기보다 나중

  → happens-before

7.3 발행 패턴

// 발행 패턴 (순서 보장)
private int[] data;
private volatile boolean initialized = false;

// 초기화
public void init() {
    data = loadData();        // 1
    initialized = true;       // 2 (volatile)
    // 1 이 2 보다 먼저 (재정렬 X)
}

// 사용
public void use() {
    if (initialized) {        // volatile 읽기
        process(data);        // data 완전 초기화됨 (보장)
    }
}

7.4 재정렬 없으면

재정렬 없으면 (volatile):

  initialized = true 가
  data 초기화보다 먼저 실행 X

  → data 준비 전에 true X
  → 안전한 발행

7.5 ILIC 의 맥락

@Service
public class OrderingGuarantee {
    
    private FreightTable table;          // 일반
    private volatile boolean ready = false;   // volatile
    
    // 초기화 (순서 보장)
    public void initialize() {
        table = loadFreightTable();   // 1. 무거운 초기화
        ready = true;                  // 2. volatile (배리어)
        // 1 이 2 보다 먼저 보장
        // table 완전 로드 후 ready
    }
    
    // 사용
    public BigDecimal calculate(Shipment shipment) {
        if (ready) {                   // volatile 읽기
            return table.lookup(shipment);   // table 완전 로드됨
        }
        return BigDecimal.ZERO;
    }
    
    private FreightTable loadFreightTable() { return new FreightTable(); }
    static class FreightTable {
        BigDecimal lookup(Shipment s) { return s.getWeight(); }
    }
}

7.6 자기 점검 답변

volatile과 순서 보장은?

:
1. 순서 문제:

  • 재정렬 (최적화)
  • 멀티 스레드 문제
  1. 순서 보장:

    • volatile 전후 재정렬 X
  2. 발행 패턴:

    • 초기화 후 플래그
  3. happens-before:

    • 순서 보장

8️⃣ DCL과 volatile

8.1 DCL

DCL (Double-Checked Locking):

  지연 초기화 + 성능:
    - 1차 확인 (락 없이)
    - 락
    - 2차 확인 (락 안)
    - 초기화

8.2 volatile 없으면

// ❌ volatile 없는 DCL (위험)
private static Singleton instance;   // volatile 없음

public static Singleton getInstance() {
    if (instance == null) {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
                // 문제: 재정렬 가능
                // 1. 메모리 할당
                // 2. instance 에 참조 대입 (재정렬!)
                // 3. 생성자 실행
                // → 다른 스레드가 미완성 객체 봄
            }
        }
    }
    return instance;
}

8.3 재정렬 문제

DCL 재정렬 문제:

  new Singleton() 은:
    1. 메모리 할당
    2. 생성자 실행
    3. instance 에 참조 대입

  재정렬 시 (1 → 3 → 2):
    - instance 에 참조 먼저
    - 생성자 아직 (미완성)
    - 다른 스레드가 미완성 객체 봄

8.4 volatile 해결

// ✓ volatile DCL (안전)
private static volatile Singleton instance;   // volatile

public static Singleton getInstance() {
    if (instance == null) {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
                // volatile 배리어로 재정렬 방지
                // 생성자 완료 후 참조 대입
            }
        }
    }
    return instance;
}

8.5 더 나은 방법

// 더 나은 방법 — Holder 패턴
public class Singleton {
    private Singleton() {}
    
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return Holder.INSTANCE;
        // 클래스 로딩 시 초기화 (JVM 보장)
        // volatile 불필요, 간단, 안전
    }
}
// 또는 enum 싱글톤

8.6 ILIC 의 맥락

@Service
public class DCLExample {
    
    // DCL + volatile (지연 초기화)
    private static volatile FreightCalculator calculator;
    
    public static FreightCalculator getCalculator() {
        if (calculator == null) {
            synchronized (DCLExample.class) {
                if (calculator == null) {
                    calculator = new FreightCalculator();   // volatile 안전
                }
            }
        }
        return calculator;
    }
    
    // 권장 — Holder 패턴 (더 간단)
    private static class CalculatorHolder {
        static final FreightCalculator INSTANCE = new FreightCalculator();
    }
    
    public static FreightCalculator getCalculatorBetter() {
        return CalculatorHolder.INSTANCE;   // volatile 불필요
    }
    
    static class FreightCalculator {}
}

8.7 자기 점검 답변

DCL과 volatile은?

:
1. DCL:

  • 이중 확인 지연 초기화
  1. volatile 없으면:

    • 재정렬 → 미완성 객체
  2. 재정렬 문제:

    • 참조 대입이 생성자보다 먼저
  3. 해결:

    • volatile (또는 Holder 패턴)

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
volatile 가시성?메인 메모리 직접
원자성?X (복합 연산)
count++ 위험?RMW 3단계 분리
적합 사용처?단일 쓰기 플래그
시나리오 3?플래그/발행/DCL
메모리 배리어?재정렬 방지
순서 보장?happens-before
DCL volatile?재정렬 방지
단일 쓰기?원자적
한계?복합 연산 X

9.2 자기 점검 체크리스트

가시성

  • 메인 메모리
  • 캐시 우회

원자성 X

  • 복합 연산
  • count++

바이트코드

  • getfield/iadd/putfield

플래그

  • 단일 쓰기

시나리오

  • 플래그/발행/DCL

배리어

  • 재정렬 방지

순서

  • happens-before

DCL

  • volatile 필수

9.3 추가 심화 질문

Q1: long/double 과 volatile?

답:

  • 32비트 JVM 에서 long/double 비원자 (word tearing)
  • volatile 이 원자적 쓰기 보장
  • 64비트 JVM 은 보통 원자적
  • volatile 로 안전 보장

Q2: volatile 배열?

답:

  • volatile int[] : 참조만 volatile
  • 배열 요소는 volatile X
  • 요소 가시성 없음
  • AtomicIntegerArray 사용

Q3: volatile vs AtomicInteger?

답:

  • volatile: 가시성, 단일 연산
  • AtomicInteger: 가시성 + 원자 (CAS)
  • 카운터는 Atomic
  • 플래그는 volatile

Q4: volatile 성능?

답:

  • 캐시 우회 (약간 느림)
  • 재정렬 제한
  • 하지만 synchronized 보다 가벼움
  • 락 없음

Q5: happens-before 규칙?

답:

  • volatile 쓰기 happens-before 읽기
  • 이전 연산 → volatile 쓰기 → 읽기 → 이후
  • JMM 보장
  • 가시성 + 순서

🎯 핵심 요약 — 3줄 정리

1. 가시성만

  • 메인 메모리 직접 R/W (가시성 ✅)
  • 복합 연산 원자성 ❌

2. count++ 위험

  • read-modify-write 3단계 (바이트코드 분리)
  • volatile 로도 손실 → Atomic/synchronized

3. 적합 시나리오

  • 단일 쓰기 플래그 (shutdown)
  • 상태 발행, DCL 인스턴스 (재정렬 방지)

📚 다음으로...

Unit 2.4 — Atomic + CAS 알고리즘 (★ 마스터)

이번 Unit에서 volatile 을 봤다면, 다음은 Atomic + CAS (★ 마스터, 면접 ★★★).

  • CAS 알고리즘 4단계
  • 락 없이 원자성 (논블로킹)
  • 3종 비교 매트릭스
  • ABA 문제
  • 마스터 Unit (50문항) + Phase 2 완주

Phase 2 진행 상황

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

5주차 누적 진행

✅ Phase 1 — 스레드 풀 필요성 (3 Unit)
🚀 Phase 2 — 동시성 안전 도구 (3/4 진행)

총: 6/26 Unit
profile
Software Developer

0개의 댓글