The producer-consumer pattern in Java 5: using blocking queues in preference to wait()/notify() (ctd)

On the previous page, we looked at using wait/notify to implement a producer-consumer pattern. As mentioned, some new Java 5 classes allow us to separate out the queue which holds pending tasks from the "real" functionality of the producer/consumer.

The BlockingQueue interface

The Java 5 concurrent package provides the BlockingQueue interface and various implementations. Blocking queues offer (among others) the following methods:

public void put(E o);
public E take();

This is a parametrised class: in other words, E, represents the type of object that we declare the queue to hold.

A common queue implementation is ArrayBlockingQueue, which has a fixed bound on the number of elements it can hold, or LinkedBlockingQueue, which need not have a limit (other than that of available memory). Using the latter, this is how our logging thread might look:

public class LoggingThread extends Thread {
  private BlockingQueue<String> linesToLog =
    new LinkedBlockingQueue<String>();

  public void run() {
    try {
      while (!terminateRequested) {
        String line = linesToLog.take();
        doLogLine(line);
      }
    } catch (InterruptedException ex) {
      Thread.currentThread().interrupt();
    }
  }

  public void log(String line) {
    linesToLog.put(line);
  }
}

The code is now cleaner since the gubbinry of synchronization and notifying is taken care of by the blocking queue. In addition, it is now simple for us to modify the code to place different requirements on the queue.

More information on blocking queues

See the following pages: