지금까지 살펴본 Object.wait() , Object.notify() 방식은 스레드 대기 집합 하나에 생산자, 소비자 스레드를 모두 관리한다.그리고 notify() 를 호출할 때 임의의 스레드가 선택된다.
따라서 앞서 살펴본 것 처럼 큐에 데이터가 없는 상황에 소비자가 같은 소비자를 깨우는 비효율이 발생할 수 있다.
또는 큐에 데이터가 가득 차있는데 생산자가 같 은 생산자를 깨우는 비효율도 발생할 수 있다.
비효율 생산자 실행

- 다음과 같은 상황을 가정하겠다.
- 큐에 "dataX"가 보관되어 있다.
- 스레드 대기 집합에는 다음 스레드가 대기하고 있다.
- 소비자: c1 , c2 , c3
- 생산자: p1 , p2 , p3
- p0 스레드가 data0 생산을 시도한다.

- p0 스레드가 실행되면서 data0를 큐에 저장한다. 이때 큐에 데이터가 가득 찬다.
- notify()를 통해 대기 집합의 스레드를 하나 깨운다.

- 만약 notify()의 결과로 소비자 스레드가 깨어나게 되면 소비자 스레드는 큐의 데이터를 획득하고, 완료된다.

- 만약 notify() 의 결과로 생산자 스레드를 깨우게 되면, 이미 큐에 데이터는 가득 차 있다. 따라서 데이터를 생 \산하지 못하고 다시 대기 집합으로 이동하는 비효율이 발생한다.
비효율 소비자 실행


- c0 스레드가 실행되고 data0를 획득한다.
- 이제 큐에 데이터는 비어있게 된다.
- c0 스레드는 notify()를 호출한다.

- 스레드 대기 집합에서 소비자 스레드가 깨어나면 큐에 데이터가 없기 때문에 다시 대기 집합으로 이동하는 비효율이 발생한다.

- 스레드 대기 집합에서 생산자 스레드가 깨어나면 큐에 데이터를 저장하고 완료된다.
같은 종류의 스레드를 깨울 때 비효율이 발생한다.
이 내용을 통해서 알 수 있는 사실은 생산자가 같은 생산자를 깨우거나, 소비자가 같은 소비자를 깨울 때 비효율이 발생 할 수 있다는 점이다. 생산자가 소비자를 깨우고, 반대로 소비자가 생산자를 깨운다면 이런 비효율은 발생하지 않는다.
스레드 기아
notify()의 또 다른 문제점으로는 어떤 스레드가 깨어날지 알 수 없기 때문에 발생할 수 있는 스레드 기아 문제가 있다.

- notify()가 어떤 스레드를 깨울지는 알 수 없다. 최악의 경우 c1 ~ c5 스레드가 반복해서 깨어날 수 있다.
- c1 이 깨어나도 큐에 소비할 데이터가 없다. 따라서 다시 스레드 대기 집합에 들어간다.
- notify()로 다시 깨우는데 어떤 스레드를 깨울지 알 수 없다. 따라서 c1 ~ c5 스레드가 반복해서 깨어날 수 있다.
- p1 은 실행 순서를 얻지 못하다가 아주 나중에 깨어날 수도 있다.
- 이렇게 대기 상태의 스레드가 실행 순서를 계속 얻지 못해서 실행되지 않는 상황을 스레드 기아(starvation) 상태라 한다.
- 물론 p1이 가장 먼저 실행될 수도 있다.
- 이런 문제를 해결하는 방법 중에 notify() 대신에 notifyAll()을 사용하는 방법이 있다.
notifyAll()
notifyAll()을사용하면 스레드 대기 집합에 있는 모든 스레드를 한번에 다 깨울 수 있다.

- 데이터를 획득한 c0 스레드가 notifyAll()을 호출한다.

- 대기 집합에 있는 모든 스레드가 깨어난다.
- 모든 스레드는 다 임계 영역 안에 있다. 따라서 락을 먼저 획득해야 한다.
- 락을 획득하지 못하면 "BLOCKED" 상태가 된다.
- 만약 c1 이 먼저 락을 먼저 획득한다면 큐에 데이터가 없으므로 다시 스레드 대기 집합에 들어간다.
- c2 ~ c5 모두 마찬가지이다.

- 따라서 p1 이 가장 늦게 락 획득을 시도해도, c1 ~ c5는 모두 스레드 대기 집합에 들어갔으므로 결과적으로 "p1"만 남게 되고, 결국 락을 획득하게 된다.(스레드 기아 문제 해결)

- p1 은 락을 획득하고, 데이터를 생성한 다음에 notifyAll()을 호출하고 실행을 완료할 수 있다.
- 참고로 반대의 경우도 같은 스레드 기아 문제가 발생할 수 있기 때문에 notifyAll() 을 호출한다.
결과적으로 notifyAll()을사용해서 스레드 기아 문제는 막을 수 있지만, 비효율을 막지는 못한다.
'멀티스레드와 동시성' 카테고리의 다른 글
| Ch09. 생산자 소비자 문제 - 생산자/소비자 대기 공간 분리 (0) | 2024.08.24 |
|---|---|
| Ch09. 생산자 소비자 문제 - Lock Condition (0) | 2024.08.24 |
| Ch08. 생산자 소비자 문제 - 예제3(wait, notify) (0) | 2024.08.23 |
| Ch08. 생산자 소비자 문제 - 예제2(생산자, 소비자 대기) (0) | 2024.08.21 |
| Ch08. 생산자 소비자 문제 - 예제1(생산자, 소비자 우선) (0) | 2024.08.20 |