자바의 정석[기초편]으로 공부한 내용을 정리한 글입니다.
핵심 요약
- wait()와 notify()는 동기화된 블록(synchronized) 안에서만 사용할 수 있고, Object 클래스에 정의되어 있습니다.
- wait()는 현재 쓰레드가 객체의 락(lock)을 풀고, waiting pool에 들어가 기다립니다.
- notify()는 waiting pool에서 하나의 쓰레드를 깨웁니다.
- notifyAll()은 모든 대기 중인 쓰레드를 깨웁니다.
synchronized void withdraw(int money) {
while(balance < money) {
wait(); // 잔액 부족 -> 대기
}
balance -= money; // 출금
}
- 출금하려 했으나 잔액 부족하면 기다립니다 (wait()로 lock 풀고 waiting pool 대기)
- 다른 쓰레드가 deposit()을 호출하면, 돈이 입금되고 notify() 호출 → 출금 쓰레드를 깨움
예제1 – 요리사와 손님 (동기화 X)
구조 설명
- Table이라는 객체를 공유함: 요리사는 Table에 음식을 add(), 손님은 Table에서 음식을 remove()
- ArrayList로 구현되어 있고, 동기화 안된 상태
if (dishes.size() >= MAX_FOOD) return;
dishes.add(dish); // 요리사
...
table.remove(food); // 손님
실행 결과 (동기화 X)
문제 발생
- 두 쓰레드가 동시에 ArrayList를 수정하다 보니 ConcurrentModificationException 발생
- 또는 한 손님이 남은 음식 먹으려는 순간 다른 손님이 먼저 먹어서 IndexOutOfBoundsException
원인
- ArrayList는 쓰레드에 안전하지 않음 (동기화 필요)
- 쓰레드 간 작업 충돌 발생
예제1 개선 (동기화 O)
해결 방법
- add()와 remove()를 synchronized로 감싸서 동기화
public synchronized void add(String dish) { ... }
public boolean remove(...) {
synchronized(this) {
while (dishes.size() == 0) { ... }
}
}
이로써 충돌은 사라지지만, 효율성 문제는 여전
실행 결과 (동기화 O)
문제점
- 예외는 발생하지 않지만, lock을 너무 오래 점유하는 문제가 발생
- 예: 손님이 음식이 없는데도 계속 Table의 lock을 잡고 있으니 요리사는 접근 못함
예제2 - wait()와 notify() 적용
문제 해결
- 손님은 음식이 없으면 wait()으로 lock을 풀고 대기
- 요리사가 음식 추가하면 notify()로 손님을 깨움
// 요리사
synchronized void add(...) {
while (dishes.size() >= MAX_FOOD) wait(); // 가득 찼으면 대기
dishes.add(...);
notify(); // 손님 깨움
}
// 손님
synchronized void remove(...) {
while (dishes.size() == 0) wait(); // 음식 없으면 대기
dishes.remove(...);
notify(); // 요리사 깨움
}
예제2 실행 결과
결과
- 요리사와 손님이 서로 lock을 오래 잡는 일이 사라짐
- 누군가 기다려야 할 상황이면 wait()로 lock을 양보하고, 조건이 충족되면 notify()로 정확하게 깨움
- 시스템이 효율적으로 돌아감 (lock 효율 ↑)
전체 정리하면:
상황 | 문제 | 해결책 |
여러 스레드가 ArrayList 공유 | 충돌 발생 | synchronized로 동기화 |
한 스레드가 lock을 오래 점유 | 효율성 ↓ | wait()과 notify()로 조건 충족 시 알림 |
'Java' 카테고리의 다른 글
함수형 인터페이스 (0) | 2025.06.28 |
---|---|
람다식이란? (0) | 2025.06.28 |
쓰레드 동기화 (0) | 2025.06.27 |
join(), yield() (0) | 2025.06.27 |
suspend(), resume() (0) | 2025.06.27 |