[문제정의]
Producer와 Consumer 가 있다.
한 쪽은 스택에 값을 지속적으로 저장하고(Producer), 다른 한 쪽은 스택의 값을 지속적으로 삭제한다.(Consumer)
Producer가 값을 너무 빠르게 저장하면 Stack overflow가 발생하며, 반대로 Consumer가 값을 너무 빠르게 삭제를
하게 되면 Stack underflow가 발생한다.
또한, 동시에 Stack에 접근하여 값을 쓰거나 삭제하려고 하면, 교착상태에 빠져버린다.
이를 해결하기 위해서 주어진 예제 프로그램에 Thread를 적용시켜서 Producer와 Consumer가 올바르게 작동하게
하는 프로그램으로 완성시켜라.
/*
* $Id: ProducerConsumer.java 8 2009-06-26 11:13:41Z DONG,Wooseok $
*/
import java.util.Random;
import java.lang.Thread;
import java.lang.Runnable;
/**
* BoundedBuffer class uses an array of int for a buffer. The size of
* the array is specified by the parameter of the constructor.
*/
class BoundedBuffer
{
/** bounded buffer data as array of int. first-in first-out (queue). */
private int[] buf;
private int queuePointer;
private int queueTop;
BoundedBuffer(int size)
{
buf = new int[size];
this.queuePointer = 0;
this.queueTop = size;
}
/**
* If the buffer is full, the current thread must wait.
*/
synchronized void insert(int i)
{
// implement here!
if (queuePointer == queueTop)
{
try
{
wait();
}
catch (InterruptedException e)
{
throw new RuntimeException(e.toString());
// TODO Auto-generated catch block
//e.printStackTrace();
}
}
else
{
buf[queuePointer] = i;
queuePointer++;
notifyAll();// consumer스래드에 notifyAll() 호출
}
}
/**
* If the buffer is empty, the current thread must wait.
*/
synchronized int remove()
{
// implement here!
if (queuePointer == 0)
{
try
{
wait();
}
catch (InterruptedException e)
{
throw new RuntimeException(e.toString());
// TODO Auto-generated catch block
//e.printStackTrace();
}// wait()
}
else
{
queuePointer--;
notifyAll();
// producer 스래드에 notifyAll() 호출
// producer 스래드의 insert() 실행
}
return 0;
}
} // end of BoundedBuffer
/**
* Producer class is a thread. It always tries to insert an object (int
* value) into the bounded buffer.
*/
class Producer implements Runnable
{
/**
* A object (int value) which is inserted into the buffer. Each time
* producer calls buf.insert(), counter is incremented by one.
* counter is shared among Producer threads (static).
*/
private static int counter = 0;
/** bounded buffer reference */
private BoundedBuffer buf;
Producer(BoundedBuffer buf)
{
this.buf = buf;
}
public void run()
{
while (true)
{
buf.insert(counter++);
try
{
Thread.sleep(SleepTimer.time());
}
catch(InterruptedException e)
{
throw new RuntimeException(e.toString());
}
}
}
}
/**
* Consumer class is a thread. It always tries to remove an object (int)
* from the bounded buffer.
*/
class Consumer implements Runnable
{
/** bounded buffer reference */
private BoundedBuffer buf;
Consumer(BoundedBuffer buf)
{
this.buf = buf;
}
public void run()
{
while(true)
{
int val = buf.remove();
System.out.println("==> " + Thread.currentThread().getName() + " threadID(" + Thread.currentThread().getId()+ ") gets" + val);
try
{
Thread.sleep(SleepTimer.longtime());
}
catch(InterruptedException e)
{
throw new RuntimeException(e.toString());
}
}
}
}
/**
* SleepTimer class provides a random number (long value) which is used
* to sleep threads. All the methods are static.
*/
class SleepTimer
{
private static final Random r = new Random();
private static final int SLEEP_TIME = 100;
private static final int LONG_SLEEP_TIME = 200;
/**
* time() returns long value between 0 (inclusive) and SLEEP_TIME
* (exclusive)
*/
static long time()
{
return r.nextInt(SLEEP_TIME);
}
/**
* longtime() returns long value between 0 (inclusive) and
* LONG_SLEEP_TIME (exclusive)
*/
static long longtime()
{
return r.nextInt(LONG_SLEEP_TIME);
}
}
/**
* ProducerConsumer class instantiates Producer threads and Consumer
* threads, and lets them start.
*/
public class ProducerConsumer
{
public static void main(String[] args)
{
// implement here!
BoundedBuffer myBuffer = new BoundedBuffer(100);
Producer myProducerA = new Producer(myBuffer);
new Thread(myProducerA).start();
Producer myProducerB = new Producer(myBuffer);
new Thread(myProducerB).start();
Producer myProducerC = new Producer(myBuffer);
new Thread(myProducerC).start();
Consumer myConsumerA = new Consumer(myBuffer);
new Thread(myConsumerA).start();
Consumer myConsumerB = new Consumer(myBuffer);
new Thread(myConsumerB).start();
Consumer myConsumerC = new Consumer(myBuffer);
new Thread(myConsumerC).start();
myBuffer.insert(0);
myBuffer.remove();
}
}
「 커 멘 트 」
まず、Thread化した時、java.lang.thread からのinheritanceすること、java.lang.runnable
interfaceから、implementsすることがります。
私は、二つの方法を全部してみましたが、runnable interfaceをimplementation しました。
queueについては、queuepointer 変数を定義して、完成させました。
insert()では、引数でもらったIを、Bufferで入れる、remove()では、queuepointerを減少させました。問題の要求と同じで、insert()する時にbufferがfullのとき、wait(),反対で、remove()する時にbufferがemptyのとき、exception handlingをしながら、wait()をしました。
もし、insertとremoveができると、nofityAll()して、wait()している他のthreadにお知らせをしました。同期化、synchronousをため、synchronized keywordを使いました。
instanceしたとき、size 10のbufferd object一つと三つのproducer object、consumer objectをつくりました。問題のとおりで、全部6個のTHREADSが、同期化しなから、BUFFERで動きました。
SLEEP_TIMEとLONG_SLEEP_TIMEを値を変化させても、 動きました。
これで要求は満足できます。
댓글
댓글 쓰기