package com.tutego.insel.thread.concurrent;

import java.util.*;
import java.util.concurrent.locks.*;

class Lager<T>
{
  private static final int MAXQUEUE = 10;

  private final Queue<T> produkte    = new LinkedList<T>();
  private final Lock lock            = new ReentrantLock();
  private final Condition nichtVoll  = lock.newCondition();
  private final Condition nichtLeer  = lock.newCondition();

  public void rein( T elem ) throws InterruptedException
  {
    lock.lock();
    try
    {
      while ( produkte.size() == MAXQUEUE )
        nichtVoll.await();

      produkte.add( elem );

      nichtLeer.signalAll();
    }
    finally {
      lock.unlock();
    }
  }

  public T raus() throws InterruptedException
  {
    lock.lock();
    try
    {
      while ( produkte.size() == 0 )
        nichtLeer.await();

      T elem = produkte.poll();

      nichtVoll.signalAll();
      return elem;
    }
    finally {
      lock.unlock();
    }
  }
}

public class ErzeugerVerbraucherDemo
{
  public static void main( String[] args )
  {
    final Lager<String> lager = new Lager<String>();

    new Thread() // Erzeuger
    {
      @Override public void run()
      {
        try
        {
          while ( true )
          {
            String s = String.format( "%1$tT, %1$tL", new Date() );

            lager.rein( s );
            System.out.println( "Produziere: " + s );

            sleep( (int) (Math.random() * 100) );
          }
        }
        catch ( InterruptedException e ) { e.printStackTrace(); }
      }
    }.start();

    class Verbraucher extends Thread
    {
      final private String name;

      Verbraucher( String name )
      {
        this.name = name;
      }

      @Override public void run()
      {
        try
        {
          while ( true )
          {
            System.out.println( name + " holt Nachricht: " + lager.raus() );

            Thread.sleep( (int) (Math.random() * 1000) );
          }
        }
        catch ( InterruptedException e ) { e.printStackTrace(); }
      }
    }

    new Verbraucher( "Eins" ).start();
    new Verbraucher( "Zwei" ).start();
    new Verbraucher( "Drei" ).start();
  }
}
