import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MultiProducerConsumer { private static final int CAPACITY = 5; private final Queue queue = new LinkedList<>(); private final Lock lock = new ReentrantLock(); private final Condition notEmpty = lock.newCondition(); private final Condition notFull = lock.newCondition(); // Producer class Producer implements Runnable { @Override public void run() { int value = 0; while (true) { lock.lock(); try { while (queue.size() == CAPACITY) { notFull.await(); } queue.offer(value); System.out.println(Thread.currentThread().getName() + " produced " + value); value++; notEmpty.signalAll(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.unlock(); } } } } // Consumer class Consumer implements Runnable { @Override public void run() { while (true) { lock.lock(); try { while (queue.isEmpty()) { notEmpty.await(); } int value = queue.poll(); System.out.println(Thread.currentThread().getName() + " consumed " + value); notFull.signalAll(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.unlock(); } } } } public static void main(String[] args) { MultiProducerConsumer pc = new MultiProducerConsumer(); // Starting multiple producers and consumers new Thread(pc.new Producer(), "Producer1").start(); new Thread(pc.new Producer(), "Producer2").start(); new Thread(pc.new Consumer(), "Consumer1").start(); new Thread(pc.new Consumer(), "Consumer2").start(); } }