BlockingQueue

핵심연산

생산자-소비자 패턴

블러킹 큐를 사용하면 take가 알아서 멈추고 대기하기 때문에 소비자 코드를 작성하기 편리하다. 생산자 역시 소비자가 여유가 없다면 대기하게 되어 구현이 용이하다.

offer 메서드를 활용하여 값을 넣을 수 없을 경우 대기하는 것이 아니라, 부하를 분배하거나 작업 내용을 직렬화 하여 disk 에 임시로 저장한다거나 소비자 스레드 수를 조정한다거나 하는 작업도 가능함.

class Producer implements Runnable {
    private final BlockingQueue queue;
 
    Producer(BlockingQueue q) {
        queue = q;
    }
 
    public void run() {
        try {
            while (true) {
                queue.put(produce());
            }
        } catch (InterruptedException ex) {
            // handling..
        }
   }
  
    Object produce() {
        // 생산
    }
 }
 
class Consumer implements Runnable {
    private final BlockingQueue queue;
 
    Consumer(BlockingQueue q) {
        queue = q;
    }
 
    public void run() {
        try {
            while (true) {
                consume(queue.take());
            }
        } catch (InterruptedException ex) {
            // handle..
        }
   }
 
    void consume(Object x) {
        // 소비
    }
 }
 
class Setup {
    void main() {
        BlockingQueue q = new SomeQueueImplementation();
 
        Producer p = new Producer(q);
  
        Consumer c1 = new Consumer(q);
        Consumer c2 = new Consumer(q);
 
  
        // thread pool을 활용하여 더 효율적으로 할수도 있고,
        // 생산자는 소비자의 상황에 맞게 값을 생성해내기 위해서는 블러킹 큐의 크기를 조절할 필요가 있음.
        //     블러킹 큐의 offer 메서드를 활용하여 소비자의 상황을 보고 소비자의 수를 늘리는 등의 동적 sizing도 생각해 볼 수 있음.
        //     또는 작업큐가 꽉차서 부하가 더이상 생산이 불가능 하다면 offer로 확인해보고 disk 등의 보조기억장치에 기록해두고 일을 계속 할수도 있음.
        new Thread(p).start();
  
        new Thread(c1).start();
        new Thread(c2).start();
    }
}