content: package org.alx.article._30_java_util_concurrent_1;
  
  import java.util.concurrent.locks.Condition;
  import java.util.concurrent.locks.Lock;
  import java.util.concurrent.locks.ReentrantLock;
  import java.util.LinkedList;
  import java.util.Queue;
  
  class SharedBuffer {
      private final Queue<Integer> buffer = new LinkedList<>();
      private final int capacity = 10;
      private final Lock lock = new ReentrantLock();
      private final Condition notFull = lock.newCondition();
      private final Condition notEmpty = lock.newCondition();
  
      public void produce(int value) throws InterruptedException {
          lock.lock();
          try {
              while (buffer.size() == capacity) {
                  notFull.await(); // Wait until the buffer has space
              }
              buffer.add(value);
              System.out.println("Produced: " + value);
              notEmpty.signal(); // Signal that the buffer is not empty
          } finally {
              lock.unlock();
          }
      }
  
      public int consume() throws InterruptedException {
          lock.lock();
          try {
              while (buffer.isEmpty()) {
                  notEmpty.await(); // Wait until the buffer is not empty
              }
              int value = buffer.poll();
              System.out.println("Consumed: " + value);
              notFull.signal(); // Signal that the buffer has space
              return value;
          } finally {
              lock.unlock();
          }
      }
  }
  
  class Producer implements Runnable {
      private final SharedBuffer buffer;
  
      public Producer(SharedBuffer buffer) {
          this.buffer = buffer;
      }
  
      @Override
      public void run() {
          int value = 0;
          try {
              while (true) {
                  buffer.produce(value++);
                  Thread.sleep(100); // Simulate time taken to produce an item
              }
          } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
          }
      }
  }
  
  class Consumer implements Runnable {
      private final SharedBuffer buffer;
  
      public Consumer(SharedBuffer buffer) {
          this.buffer = buffer;
      }
  
      @Override
      public void run() {
          try {
              while (true) {
                  buffer.consume();
                  Thread.sleep(150); // Simulate time taken to consume an item
              }
          } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
          }
      }
  }
  
  public class ConditionProducerConsumerExample {
      public static void main(String[] args) {
          SharedBuffer buffer = new SharedBuffer();
          Thread producerThread = new Thread(new Producer(buffer));
          Thread consumerThread = new Thread(new Consumer(buffer));
  
          producerThread.start();
          consumerThread.start();
      }
  }