import java.util.Date; // Main Factory class public class Factory { public static void main(String[] args) { // Create the message queue Channel queue = new MessageQueue<>(); // Create the producer and consumer threads and pass // each thread a reference to the MessageQueue object Thread producer = new Thread(new Producer(queue)); Thread consumer = new Thread(new Consumer(queue)); // Start the threads producer.start(); consumer.start(); } } // Producer class class Producer implements Runnable { private final Channel queue; public Producer(Channel queue) { this.queue = queue; } public void run() { Date message; while (true) { // Nap for a while SleepUtilities.nap(); // Produce an item and enter it into the buffer message = new Date(); System.out.println("Producer produced: " + message); queue.send(message); } } } // Consumer class class Consumer implements Runnable { private final Channel queue; public Consumer(Channel queue) { this.queue = queue; } public void run() { Date message; while (true) { // Nap for a while SleepUtilities.nap(); // Consume an item from the buffer message = queue.receive(); System.out.println("Consumer consumed: " + message); } } } // Channel interface interface Channel { void send(E item); E receive(); } // MessageQueue class implementing Channel interface class MessageQueue implements Channel { private final java.util.Queue queue = new java.util.LinkedList<>(); private final int capacity = 10; public synchronized void send(E item) { while (queue.size() == capacity) { try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } queue.add(item); notifyAll(); } public synchronized E receive() { while (queue.isEmpty()) { try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } E item = queue.poll(); notifyAll(); return item; } } // SleepUtilities class class SleepUtilities { public static void nap() { try { Thread.sleep((long) (Math.random() * 1000)); // Sleep for up to 1 second } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }