# 소스
class CircularQueue{
private int contents[], size;
private int head, tail;
private int count;
public CircularQueue(int sz) {
size = sz;
head = tail = 0;
count = 0;
contents = new int[size];
}
public synchronized int get(String name) {
int res;
while (count == 0)
try { wait();
} catch (InterruptedException e) {}
res = contents[tail];
System.out.println(name + " got: " + contents[tail]);
tail = (tail + 1) % size;
notify();
count--;
return res;
}
public synchronized void put(int value, String name) {
while(count == size)
try { wait();
} catch (InterruptedException e) {}
contents[head] = value;
System.out.println(name + " put: " + contents[head]);
head = (head + 1) % size;
notify();
count++;
}
}
class Producer extends Thread{
private CircularQueue boundedBuffer;
private String number;
public Producer(CircularQueue c, String number) {
super("Producer #" + number);
boundedBuffer = c;
this.number = number;
}
public void run() {
for (int i = 0; i < 10; i++) {
boundedBuffer.put(i, getName());
try {
sleep((int)(Math.random() * 100));
} catch (InterruptedException e) {}
}
}
}
class Consumer extends Thread{
private CircularQueue boundedBuffer;
private String number;
public Consumer(CircularQueue c, String number) {
super("Consumer #" + number);
boundedBuffer = c;
this.number = number;
}
public void run() {
int value = 0;
for (int i = 0; i < 10; i++) {
value = boundedBuffer.get(getName());
}
}
}
public class ch11_11 {
public static void main(String[] args) {
CircularQueue c = new CircularQueue(2);
Producer p1 = new Producer(c, "1");
Producer p2 = new Producer(c, "2");
Consumer c1 = new Consumer(c, "1");
Consumer c2 = new Consumer(c, "2");
p1.start();
p2.start();
c1.start();
c2.start();
}
}
# 프로그램 설명
1. 환형 큐(CircularQueue)에 대한 클래스를 정의한다.
- 환형 큐는 한쪽 끝에서 삽입이 일어나고 다른 한쪽에서 제거가 일어난다.
- head에 데이터를 삽입하고 tail에서 데이터를 제거한다.
- 큐의 내용을 담을 1차원 배열 contents와 큐의 크기 변수 size를 선언한다.
- 큐의 head와 tail 변수를 선언한다.
- 큐 내에 있는 원소의 수를 셀 변수 count를 선언한다.
- CircularQueue 클래스의 하나의 매개변수를 가지는 생성자 CircularQueue(int sz)를 선언한다. 이 생성자는 sz를 입력받아 클래스 내의 변수 size에 초기화하고 head와 tail을 0으로 초기화한다. 큐의 내용인 contents를 큐의 size만큼의 크기를 갖는 배열로 생성한다.
- 큐의 tail에서 데이터를 제거하는 메소드 int get(int number)를 동기화 메소드로 선언하여 둘 이상의 실행 스레드가 서로 간섭할 수 없도록 한다. 즉 생산자와 소비자의 행동이 독립적으로 수행되도록 하기 위해서이다. 큐의 tail 부분의 데이터를 저장할 변수 res를 선언한다. 만약 큐에 데이터가 없어(count가 0이면) 제거할 데이터가 없는 경우 wait() 메소드를 이용하여 스레드가 제거할 데이터가 생길 때까지 기다린다. 제거할 데이터가 있으면 변수 res에 큐의 tail 부분의 데이터를 저장하고 소비자 클래스에 getName() 메소드로 넘겨받은 소비자의 번호(스레드 이름)와 제거된 데이터(contenst[tail], 즉 res)를 화면에 출력한다. tail의 값을 (tail + 1) % size로 설정하여 다음으로 제거될 데이터의 위치를 설정한다. 데이터를 제거한 후 하나의 스레드를 깨우고 원소의 수를 1 감소시키고 제거한 데이터를 리턴 한다.
- 큐의 head에 데이터를 삽입하는 메소드 void put(int value, int number)를 동기화 메소드로 선언하여 get() 메소드와 같이 둘 이상의 실행 스레드가 서로 간섭할 수 없도록 한다. 만약 큐가 다 차서(count가 size와 동일하면) 데이터 삽입이 불가능한 경우 wait() 메 소드를 이용하여 스레드가 큐에 공간이 생겨 데이터 삽입이 가능할 때까지 기다린다. 큐에 데이터를 입력 가능하면 value 값을 입력받아 이를 큐의 head 부분에 삽입한다. 생산자 클래스에서 getName() 메소드로 넘겨받은 생산자의 번호(스레드 이름)와 head부분에 삽입된 데이터 (contens[head], 즉 value)를 화면에 출력한다. head의 값을 (tail + 1) % size로 설정하여 다음으로 삽입될 데이터의 위치를 설정한다. 이 때 % size를 하는 이유는 OutOfBoundsException이 일어나지 않고 다시 배열의 첫 번째 부분에 삽입을 가능하게 하기 위해서(순환)이다. 데이터가 입력되었으니 하나의 스레드를 깨우고 원소의 수를 1 증가시킨다.
2. 생산자(Producer)에 대한 클래스를 정의한다.
- 환형 큐를 사용하여 버퍼를 선언한다.
- 생산자의 번호를 저장할 변수 number를 선언한다.
- Producer 클래스의 두 개의 매개변수를 가지는 생성자 Producer(CircularQueue c, String number)를 선언한다. 이는 super 클래스에 생산자의 번호를 저장하고 버퍼를 초기화하고 생산자의 번호를 클래스 내의 변수 number에 초기화한다.
- 데이터를 생산하는 void run() 메소드를 선언한다. 이 메소드는 0부터 9사이의 정수를 생성하여 버퍼에 넣는 작업을 한다. 버퍼에 넣을 때 마다 put() 메소드에 getName() 메소드를 사용해서 실행 중인 스레드의 이름(생산하고 있는 생산자의 번호)을 넘겨주어 생산자의 번호와 넣은 데이터가 출력된다. 이때 다음 단계의 생성 전에 0에서 100밀리초 사이의 임의의 시간 동안 생산자가 sleep 하도록 설정했다.
3. 소비자(Consumer)에 대한 클래스를 정의한다.
- 환형 큐를 사용하여 버퍼를 선언한다.
- 소비자의 번호를 저장할 변수 number를 선언한다.
- Consumer 클래스의 두 개의 매개변수를 가지는 생성자 Cosumer(CircularQueue c, String number)를 선언한다.
이는 super 클래스에 소비자의 번호를 저장하고 버퍼를 초기화하고 소비자의 번호를 클래스 내의 변수 number에
초기화한다.
- 데이터를 소비하는 void run() 메소드를 선언한다. 이 메소드는 0부터 9사이의 정수를 소비하여 버퍼에서 가져오는 작업을 한다. 버퍼에서 가져올 때마다 get() 메소드에 getName() 메소드를 이용하여 실행 중인 스레드의 이름을 넘겨주어(소비하고 있는 소비자의 번호) 소비자의 번호와 가져온 데이터가 출력된다.
4. main() 문을 선언한다.
- 버퍼를 환형 큐 클래스를 이용하여 객체를 생성하고 버퍼의 크기를 2로 설정한다.
- 생산자 2명, 소비자를 2명을 생산자, 소비자 클래스의 객체로 생성한다.
- 생산자 2명, 소비자 2명에 대한 스레드를 실행시킨다.
# 실행 결과
# 실행 결과 설명