synchronized 원리 완벽 이해하기
지금부터가 진짜 멀티스레드의 시작입니다.
앞에서 배운:
프로세스
↓
스레드
↓
Heap 공유
때문에 발생하는 가장 대표적인 문제가 있습니다.
바로:
Race Condition (경쟁 상태)
입니다.
그리고 이 문제를 해결하기 위해 Java가 가장 먼저 제공한 것이:
synchronized
입니다.
실무 면접에서도:
synchronized 원리를 설명해주세요.
는 정말 자주 나오는 질문입니다.
대표 이미지



1. Race Condition이란?
예:
public class Counter {
int count = 0;
public void increase() {
count++;
}
}
2. 스레드 2개가 동시에 실행
Thread A
Thread B
동시에:
count++;
실행.
3. 예상
10000번 증가
+
10000번 증가
=
20000
4. 실제
18342
19782
19901
등.
매번 다름.
5. 왜 그럴까?
count++ 는 사실 한 줄이 아닙니다.
6. JVM 관점
실제로는:
count++;
↓
1. count 읽기
2. +1 계산
3. count 저장
7. 문제 상황
count = 5
Thread A
읽기 → 5
Thread B
읽기 → 5
Thread A
저장 → 6
Thread B
저장 → 6
결과
7이 되어야 하는데
6
8. 이것이 Race Condition
Race condition
9. 해결 방법
한 번에 한 스레드만 실행.
즉:
Thread A 실행 중
↓
Thread B 대기
10. synchronized 등장
예:
public synchronized void increase() {
count++;
}
11. 의미
동시에 하나의 Thread만 진입 가능
12. 결과
Thread A
↓
작업
↓
종료
그 다음
Thread B
13. synchronized 내부 원리
매우 중요.
Java는
Monitor Lock
기반으로 동작.
14. Monitor란?
Monitor
한 줄 정의
객체가 가진 락(Lock)
15. 모든 객체는 락을 가진다
놀랍지만 사실.
예:
Object obj = new Object();
obj 내부
Object Header
↓
Monitor 정보
존재.
16. synchronized 메서드
public synchronized void increase()
실제로는
this Monitor 획득
↓
메서드 실행
↓
Monitor 반환
17. 그림으로 보면
Thread A
↓
Lock 획득
↓
실행
↓
Lock 해제
Thread B
↓
대기
18. synchronized 블록
메서드 전체 말고
일부만 가능.
public void increase() {
synchronized(this) {
count++;
}
}
19. 의미
synchronized 영역만 보호
20. Lock 대상
매우 중요.
synchronized(this)
↓
현재 객체 락
21. 다른 객체 사용 가능
private final Object lock =
new Object();
synchronized(lock) {
}
22. 왜 별도 Lock 객체 사용?
실무에서 많이 사용.
synchronized(this)
는
외부 코드도 락 가능.
synchronized(lock)
는
내부 전용.
23. synchronized는 재진입 가능
매우 중요.
예:
public synchronized void a() {
b();
}
public synchronized void b() {
}
24. 데드락 안 걸림
왜?
같은 Thread는
이미 락 보유 중.
25. 이것을
Reentrant Lock
이라고 함.
26. synchronized는 공정할까?
아니오.
예:
A 대기
B 대기
C 대기
반드시
A
↓
B
↓
C
순서 아님.
JVM이 결정.
27. synchronized의 단점
성능 비용
락 획득 필요.
Context Switch 증가
대기
↓
깨움
비용 발생.
병렬성 감소
동시에 실행 불가.
28. 그래서 최소 범위 권장
안 좋은 예
public synchronized void process() {
DB조회
API호출
파일저장
}
29. 좋은 예
public void process() {
synchronized(lock) {
count++;
}
API 호출
}
락 범위를 최소화.
30. synchronized 내부 최적화
JDK 6 이후
많은 최적화 추가.
31. Biased Lock
예전 JVM 최적화.
아이디어
항상 같은 Thread만 사용
이면
락 검사를 생략.
※ JDK 15 이후 사실상 제거 수순.
32. Lightweight Lock
경쟁 적을 때.
OS Mutex 사용 안 함.
CAS 기반 처리.
33. Heavyweight Lock
경쟁 심함.
OS 수준 락 사용.
Context Switch 발생.
34. JVM 내부 흐름
Biased
↓
Lightweight
↓
Heavyweight
점점 무거워짐.
35. synchronized는 언제 필요할까?
대표:
공유 변수 수정
공유 컬렉션 수정
상태 변경
36. 필요 없는 경우
지역 변수.
public void test() {
int x = 0;
}
지역 변수는
Stack
에 존재.
스레드 공유 안 함.
37. 면접 단골 질문
Q. synchronized는 무엇을 보호하나요?
Critical Section
Q. Lock은 어디에 있나요?
객체 Monitor
Q. synchronized(this) 의미는?
현재 객체 락 획득
Q. synchronized는 재진입 가능한가?
가능
(Reentrant)
Q. synchronized는 공정한가?
아니오
38. Critical Section
매우 중요.
한 줄 정의.
동시에 실행되면 안 되는 코드 영역
예:
count++;
대표적인 Critical Section.
39. 핵심 흐름 요약
여러 Thread
↓
공유 Heap 접근
↓
Race Condition 발생
↓
synchronized
↓
Monitor Lock 획득
↓
한 Thread만 실행
↓
Lock 반환
40. 가장 중요한 핵심 한 줄
synchronized는 객체의 Monitor Lock을 이용해 Critical Section에 한 번에 하나의 스레드만 진입하도록 보장하는 Java의 기본 동기화 메커니즘이다.
41. 실무에서 반드시 알아야 할 다음 단계
synchronized를 이해했다면 바로 다음에 나오는 질문이 있습니다.
그런데 count 값을 읽기만 할 때도 synchronized가 필요할까?
여기서 등장하는 것이:
volatile 키워드
입니다.
다음 글에서는:
- CPU Cache
- Memory Visibility
- Cache Coherency
- Happens-Before
까지 포함해서
volatile 키워드를 깊게 설명하겠습니다.
'language > java' 카테고리의 다른 글
| CAS(Compare And Swap) 완벽 이해하기 (0) | 2026.05.29 |
|---|---|
| volatile 키워드 완벽 이해하기 (0) | 2026.05.29 |
| Thread와 Runnable 완벽 이해하기 (0) | 2026.05.29 |
| 프로세스(Process) vs 스레드(Thread) 완벽 이해하기 (0) | 2026.05.29 |
| Spring MVC 예외 처리 전체 흐름 완벽 이해하기 (0) | 2026.05.29 |
댓글