
멀티스레드 프로그래밍을 하다 보면 생산자-소비자 문제(Producer-Consumer Problem)를 자주 만나게 됩니다. 이 문제는 생산자가 데이터를 생성하고, 소비자가 그 데이터를 소비하는 과정에서 발생하는 동시성 문제입니다.
생산자(Producer)와 소비자(Consumer)가 한정된 버퍼(Buffer)를 통해 데이터를 주고받는 상황을 가정합니다.
이를 해결하기 위해 생산자는 버퍼가 가득 찼을 때 대기, 소비자는 버퍼가 비었을 때 대기해야 합니다.
생산자-소비자 문제는 결국 버퍼의 크기가 제한되어 있기 때문에 발생합니다. 이를 해결하기 위해 스레드 동기화(Synchronization)가 필요합니다.
자바에서는 wait()과 notify()를 사용하여 이 문제를 해결할 수 있습니다.
wait() 메서드notify()를 호출하면 다시 실행됨.notify() 메서드wait() 상태에서 대기 중인 스레드 중 하나를 깨움.notifyAll() 메서드wait() 상태에서 대기 중인 모든 스레드를 깨움.아래는 wait()와 notify()를 사용하여 생산자가 버퍼가 가득 찼을 때 대기하고, 소비자가 버퍼가 비었을 때 대기하는 코드입니다.
package thread.bounded;
import java.util.ArrayDeque;
import java.util.Queue;
import static util.MyLogger.log;
public class BoundedQueueV3 implements BoundedQueue {
private final Queue<String> queue = new ArrayDeque<>();
private final int max;
public BoundedQueueV3(int max) {
this.max = max;
}
@Override
public synchronized void put(String data) {
while (queue.size() == max) {
log("[put] 큐가 가득 참. 생산자 대기");
try {
wait(); // 큐가 가득 찼으므로 대기
log("[put] 생산자 깨어남");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
queue.offer(data);
log("[put] 생산자 데이터 저장, notify() 호출");
notify(); // 대기 중인 소비자 깨움
}
@Override
public synchronized String take() {
while (queue.isEmpty()) {
log("[take] 큐에 데이터가 없음, 소비자 대기");
try {
wait(); // 큐가 비었으므로 대기
log("[take] 소비자 깨어남");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
String data = queue.poll();
log("[take] 소비자 데이터 획득, notify() 호출");
notify(); // 대기 중인 생산자 깨움
return data;
}
@Override
public String toString() {
return queue.toString();
}
}
put 메서드)synchronized를 사용하여 동기화.wait()을 호출하여 락을 반납하고 대기.notify()를 호출하여 대기 중인 소비자를 깨움.take 메서드)synchronized를 사용하여 동기화.wait()을 호출하여 락을 반납하고 대기.notify()를 호출하여 대기 중인 생산자를 깨움.wait()).notify()).wait()).notify()).wait()와 notify()를 사용하면 생산자-소비자 문제를 효과적으로 해결할 수 있다.wait()와 notify()를 사용해야 한다.이렇게 하면 생산자가 데이터를 버리거나, 소비자가 빈 데이터를 가져가는 문제를 해결할 수 있습니다! 🚀