CAS(Compare And Swap) 완벽 이해하기
이전 글에서 배운 내용을 먼저 정리해보자.
멀티스레드
↓
Race Condition 발생
↓
synchronized 사용
↓
문제 해결
그런데 문제가 하나 있다.
synchronized는 안전하지만 비싸다.
왜냐하면:
Lock 획득
↓
대기
↓
Context Switch
↓
Lock 해제
과정이 필요하기 때문이다.
그래서 CPU 제조사와 JVM 개발자들은 고민했다.
락을 사용하지 않고도 안전하게 값을 변경할 수 없을까?
여기서 등장한 것이:
CAS (Compare And Swap)
이다.
1. CAS란?
한 줄 정의.
현재 값이 내가 예상한 값이면 변경하고,
아니면 실패하는 원자적(Atomic) 연산
2. 이름 의미
CAS
Compare
↓
비교하고
And
Swap
↓
교체
3. 예제
현재 값
count = 10
Thread A
10이라고 생각
CAS 요청
CAS(10, 11)
의미
현재 값이 10이면
11로 바꿔라
4. 결과
현재 값
10
이므로
11
변경 성공.
5. 다른 경우
현재 값
count = 12
CAS
CAS(10, 11)
결과
실패
왜?
내가 예상한 값
=
10
실제 값
=
12
다르기 때문.
6. 중요한 특징
CAS는
비교 + 변경
이
한 번에
수행된다.
7. 왜 중요할까?
만약
비교
↓
변경
이 따로 수행되면
중간에 다른 Thread가 끼어들 수 있다.
CAS는 CPU가 제공하는 특수 명령어로
비교
+
변경
을 하나의 원자적 연산으로 처리한다.
8. Atomic이란?
Atomic
더 이상 쪼갤 수 없는 연산
예:
count++;
사실은
읽기
+
1
+
쓰기
3단계.
Atomic 아님.
9. CAS는 Atomic
비교
+
쓰기
가
한 번에 수행됨.
10. synchronized와 비교
synchronized
문 잠금
↓
작업
↓
문 열기
CAS
문 안 잠금
↓
변경 시도
↓
실패하면 재시도
11. CAS 동작 예시
초기값
count = 0
Thread A
0 읽음
Thread B
0 읽음
Thread A
CAS(0,1)
성공.
현재 값
1
Thread B
CAS(0,1)
실패.
왜?
현재 값
=
1
12. Thread B는?
다시 시도.
1 읽음
↓
CAS(1,2)
↓
성공
13. 이것이 Lock-Free
중요.
락 없이 동작
한다.
14. Lock-Free란?
락을 사용하지 않고
동시성 문제를 해결하는 기법.
15. JVM에서 CAS
실제로는
Unsafe.compareAndSwapInt()
같은 JVM 내부 명령 사용.
(최신 JDK는 VarHandle 기반)
16. CPU 명령어
대표적으로
CMPXCHG
명령 사용.
(x86 기준)
CPU가 직접 지원.
17. Java에서 어디에 쓰일까?
대표적으로
AtomicInteger
18. 예제
AtomicInteger count =
new AtomicInteger();
증가
count.incrementAndGet();
19. 내부 구현
대략
for (;;) {
int current = value;
int next = current + 1;
if (CAS(current, next)) {
return next;
}
}
20. 왜 for 무한루프?
CAS 실패 가능.
실패하면
다시 읽기
↓
다시 CAS
반복.
21. Spin Lock
이 방식을
Spin
이라고 한다.
계속 돌면서 시도.
22. 장점
락 없음.
Context Switch 없음.
빠름.
23. 단점
경쟁 심하면
실패
↓
재시도
↓
실패
↓
재시도
계속 반복.
CPU 사용량 증가.
24. 언제 유리할까?
경쟁 적을 때.
예:
99% 성공
매우 빠름.
25. 언제 불리할까?
경쟁 심할 때.
100개 Thread
가 동시에 수정.
CAS 실패 폭증.
26. 그래서
CAS ≠ 무조건 좋음
상황에 따라 다름.
27. ABA 문제
CAS의 유명한 문제.
면접 단골.
현재 값
A
Thread A
A 읽음
그 사이
Thread B
A → B → A
변경.
28. Thread A 관점
A 그대로네?
CAS 성공.
하지만 실제로는
중간에 변경됨
이것이
ABA Problem
29. 해결
대표적으로
AtomicStampedReference
사용.
30. 버전 관리
예:
A, version=1
↓
B, version=2
↓
A, version=3
이제 구분 가능.
31. synchronized vs CAS
| 항목 | synchronized | CAS |
| Lock 사용 | O | X |
| Context Switch | O | X |
| Atomicity | O | O |
| 경쟁 적을 때 | 느림 | 빠름 |
| 경쟁 심할 때 | 안정적 | 재시도 증가 |
32. CAS와 volatile 관계
매우 중요.
AtomicInteger 내부
private volatile int value;
왜?
CAS는
Atomicity
제공.
volatile은
Visibility
제공.
둘 다 필요.
33. 실제 AtomicInteger 구조
개념적으로
class AtomicInteger {
volatile int value;
incrementAndGet() {
CAS ...
}
}
34. 실무에서 자주 쓰는 Atomic 클래스
대표:
AtomicInteger
AtomicInteger
AtomicLong
AtomicBoolean
AtomicReference
35. 면접 단골 질문
Q. CAS란?
현재 값이 예상값과 같을 때만 변경하는 원자적 연산
Q. CAS는 Lock을 사용하는가?
아니오
Q. CAS 실패 시?
재시도
Q. AtomicInteger는 무엇으로 구현되나?
volatile + CAS
Q. CAS 문제점은?
ABA 문제
36. 핵심 흐름 요약
값 읽기
↓
예상값 계산
↓
CAS 시도
↓
성공 → 종료
실패 → 재시도
37. synchronized → volatile → CAS 흐름
지금까지 배운 내용을 연결하면:
Race Condition
↓
synchronized
↓
Lock 비용 발생
↓
volatile
↓
Visibility 해결
↓
CAS
↓
Lock-Free Atomic 연산
38. 가장 중요한 핵심 한 줄
CAS는 "현재 값이 예상한 값과 같을 때만 변경"하는 CPU 수준의 원자적 연산이며, AtomicInteger 같은 Lock-Free 동시성 클래스의 핵심 기반 기술이다.
39. 다음 글 예고
다음 글은:
Atomic 클래스 (AtomicInteger, AtomicLong 등)
입니다.
CAS를 실제 Java 코드에서 어떻게 활용하는지, 그리고 왜 count++ 대신 AtomicInteger.incrementAndGet()을 사용하는지 실무 관점에서 깊게 설명하게 됩니다.
'language > java' 카테고리의 다른 글
| Thread-safe 컬렉션 완벽 이해하기 (0) | 2026.05.29 |
|---|---|
| Atomic 클래스 (AtomicInteger, AtomicLong 등) 완벽 이해하기 (0) | 2026.05.29 |
| volatile 키워드 완벽 이해하기 (0) | 2026.05.29 |
| synchronized 원리 완벽 이해하기 (0) | 2026.05.29 |
| Thread와 Runnable 완벽 이해하기 (0) | 2026.05.29 |
댓글