원자적 연산이란 무엇인가? i++; 은 원자적 연산인가?
- 원자적 연산의 의미는 해당 연신이 더 이상 나눌 수 없는 단위로 수행된다는 것을 의미
- 예를 들어서 i = 1 은 원자적 연산이다.
- i ++ (i = i + 1 )은 원자적 연산이 아니며 다음과 같이 세 파트로 나눠질 수 있다.
- 오른쪽에 있는 i의 값을 읽는다
- 읽은 i의 값에 1을 더한다.
- 더해진 값을 왼쪽 i에 대입한다.
원자적 연산과 동시성 문제의 상관 관계에 대해 설명하시오
- 원자적 연산일 경우 동시성 문제가 발생하지 않고, 그렇지 않을 경우 동시성 문제가 발생한다.
- i = i + 1의 경우를 예로 들어보자. (i의 기존 값이 10이라고 가정하자)
- 1. 오른쪽 i의 조회된 값은 10이다.
- 2. 조회된 10에 1을 더한다.
- 3. 그 이후 11을 왼쪽 i에 대입한다.
- 하지만 다른 스레드에서 이미 1번 이후에 i의 값을 12로 바꿨으면, 이 작업은 사실 i에서 1을 더한 13이 되야 하므로 동시성 문제가 발생한 케이스라고 할 수 있다.
위 i = i + 1 은 원자적 연산이 아니라 동시성 문제를 해결하려면 Lock을 걸어서 해결해야하지만 Lock을 걸지 않고도 동시성 문제를 해결할 수 있는 방법이 있다. 그 방법에 대해 자세히 설명하시오

- 그 방법은, CAS(CompareAnd-Swap, Compare-And-Set) 연산이다.
- 락을 걸지 않아도 되는 이유는 그 여러 작업에 대한 연산을 하드웨어 단에서 동시에 처리가 가능하기 때문.
- CPU에서 메인메모리에 있는 값을 읽고, 그 값이 우리가 조회한 값이 맞다면 우리가 원하는 값으로 변경한다.
- 조회 및 변경이므로 원자적 연산이 아니지만, 하드웨어단에서 이걸 원자적으로 처리하는 기능을 제공함.
CAS와 Lock 방식의 장단점을 설명하시오
비교 요약 표
| 비교 항목 | Lock 방식 | CAS 방식 |
| 접근 철학 | 비관적 접근 (Pessimistic) | 낙관적 접근 (Optimistic) |
| 락 사용 여부 | 사용 | 사용하지 않음 |
| 데이터 접근 방식 | 락 획득 후 접근 | 충돌 발생 시 재시도 |
| 성능 | 스레드 경쟁 시 성능 저하 | 충돌이 적을 때 높은 성능 |
| 안전성 | 높은 일관성 보장 | 충돌 발생 시 재시도 필요 |
| 적용 사례 | 스레드 경쟁이 많을 때 유리 | 충돌이 적을 때 유리 |
- Lock 방식은 매번 Lock을 걸고 Runnable -> Waiting -> Runnable 로 상태 변환, Context Swtiching이 일어나야 하므로 성능 저하가 발생할 수 있음.
- 반면에, CAS는 Lock 과정이 없이 하드웨어단에서 처리되므로 성능이 훨씬 높음.
- 문제는, CAS 방식은 하드웨어단에서 값을 조회 후 값이 맞다면 값을 변경하기 때문에, 너무 많은 쓰레드가 동시에 작업을 한다면 값을 조회 후 값이 틀린 경우에 계속 다시 시도해서 성능이 떨어질 가능성이 있음.
- 따라서, 스레드간 경쟁이 너무 심한 경우는 Lock 방식이 더 나을 수도 있음.
- 하지만 하드웨어의 연산은 1초에도 수십억건을 할 만큼 충돌이 생각보다 잘 나지 않기 때문에 실무단에서는 사실상 충돌이 그렇게 많은 경우는 적다고 판단 가능함.
'김영한의 실전 자바 - 고급 1편' 카테고리의 다른 글
| 김영한의 실전 자바 - 고급 1편(Executor) (0) | 2025.01.13 |
|---|---|
| 김영한의 실전 자바 - 고급 1편(동시성 컬렉션) (0) | 2025.01.11 |
| 김영한의 실전 자바 - 고급 1편(생산자 소비자 문제: Object - wait/notify, ReentarantLock - await/signal, BlockingQueue) (1) | 2025.01.08 |
| 김영한의 실전 자바 - 고급 1편(volatile, synchronized, LockSupport, ReentrantLock) (1) | 2025.01.05 |
| 김영한의 실전 자바 - 고급 1편(스레드 생명주기, join, interrupt, yield) (2) | 2025.01.04 |