BlockingQueue producer-consumer
Wire producers to consumers with a bounded queue that does all the waiting for you.
Open this lesson in the learning hubKey points
BlockingQueueis the producer-consumer pattern already written and tested. No hand-rolledwait/notifyneeded.put()blocks while the queue is full,take()blocks while it is empty. That blocking is your back-pressure.- Always bound it.
ArrayBlockingQueueor a sizedLinkedBlockingQueue. An unbounded queue turns a slow consumer into an OutOfMemoryError. - When dropping work beats waiting, use
offer(timeout)andpoll(timeout)instead. - Signal the end with a poison pill, one per consumer, so every consumer gets its own exit ticket.
Example
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Main {
static final String DONE = "__done__";
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new ArrayBlockingQueue<>(4); // bounded = back-pressure
Thread producer = new Thread(() -> {
try {
for (int i = 1; i <= 8; i++) queue.put("item-" + i); // blocks while full
queue.put(DONE); // poison pill
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
});
Thread consumer = new Thread(() -> {
try {
while (true) {
String item = queue.take(); // blocks while empty
if (DONE.equals(item)) break;
System.out.println("consumed " + item);
Thread.sleep(20); // slow consumer on purpose
}
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
});
producer.start(); consumer.start();
producer.join(); consumer.join();
System.out.println("queue empty: " + queue.isEmpty());
}
}
A bounded queue is back-pressure you get for free.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Multithreading course, and every lesson in it is listed on the Multithreading contents page.