Java 如何阻止,直到阻止队列为空?

Java 如何阻止,直到阻止队列为空?,java,concurrency,blockingqueue,Java,Concurrency,Blockingqueue,我正在寻找一种方法来阻止,直到BlockingQueue为空 我知道,在多线程环境中,只要有生产者将项目放入BlockingQueue,就可能出现队列变空,几纳秒后就充满项目的情况 但是,如果只有一个生产者,那么它可能希望在停止将项目放入队列后等待(并阻止)直到队列为空 Java/伪代码: // Producer code BlockingQueue queue = new BlockingQueue(); while (having some tasks to do) { queue

我正在寻找一种方法来阻止,直到
BlockingQueue
为空

我知道,在多线程环境中,只要有生产者将项目放入
BlockingQueue
,就可能出现队列变空,几纳秒后就充满项目的情况

但是,如果只有一个生产者,那么它可能希望在停止将项目放入队列后等待(并阻止)直到队列为空

Java/伪代码:

// Producer code
BlockingQueue queue = new BlockingQueue();

while (having some tasks to do) {
    queue.put(task);
}

queue.waitUntilEmpty(); // <-- how to do this?

print("Done");
//生产者代码
BlockingQueue=新建BlockingQueue();
(有一些任务要做){
queue.put(任务);
}

queue.waitUntilEmpty();// 使用
wait()
notify()
的简单解决方案:


这并不完全是您想要做的,但是使用
SynchronousQueue
将产生与Java/伪代码非常相似的效果,即生产者阻塞,直到某个消费者检索到所有数据


唯一的区别是生产者在每次put上阻塞,直到消费者来检索数据,而不是在最后只执行一次。不确定这是否会对你的情况产生影响。如果制作人执行的任务有点昂贵,我希望它只会产生显著的不同

您的用例应该非常特殊,因为大多数情况下,您只希望在队列已满时阻止生产者,而不是等到队列为空

无论如何,这是可行的。我相信直到
isEmpty
返回true为止的旋转并不是那么低效,因为生产者将在本地旋转,即访问自己的缓存,而不是撞击总线。然而,由于线程保持可调度性,这将消耗CPU时间。但本地纺纱肯定是更容易的方式。否则,我会看到两种选择:

  • 使用
    等待
    +
    通知
    如@niculare建议
  • 以某种方式使第一个通知队列的消费者为空,以无锁方式通知生产者;这将是缓慢的,但降级“更”优雅

  • 我知道你可能已经有很多线程在积极地轮询或排队,但我仍然觉得你的流/设计不太正确

    队列变为空并不意味着之前添加的任务已完成,有些项目可能需要很长时间才能处理,因此检查是否为空并不太有用

    因此,您应该忘记
    阻塞队列
    ,您可以将其用作任何其他集合。将项目转换为
    可调用的
    集合
    ,并使用
    ExecutorService.invokeAll()

    收集队列=。。。
    收集任务=新建ArrayList();
    用于(项目:队列){
    tasks.add(newcallable()){
    @凌驾
    公共结果调用()引发异常{
    //处理项目。。。
    返回结果;
    }
    });
    }
    //查看结果,如有必要,为invokeAll添加超时
    列表结果=executorService.invokeAll(任务);
    //完成
    
    这种方法可以让您完全控制制作人可以等待的时间和适当的异常处理,
    BlockingQueue可以通过以下方法在“删除”时被阻止:
    take()
    poll(时间、单位)
    而不是
    poll()

    niculare给出的答案似乎没有问题,但请查看@hankduan的评论

    我在寻找类似问题的解决方案时看到了这个问题。
    最后,我或多或少地重写了
    LinkedBlockingQueue

    它有其方法的子集,并且不实现
    集合
    Iterable

    它管理多个生产者和消费者。
    对我来说这很有效

    /**********************************************************************************************************************
     * Import specifications
     *********************************************************************************************************************/
    import java.util.Date;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.*;
    
    /**********************************************************************************************************************
     * This class implements a completely reentrant FIFO.
     *********************************************************************************************************************/
    public class BlockingFIFO<E>
    {
      /********************************************************************************************************************
       * The constructor creates an empty FIFO with a capacity of {@link Integer#MAX_VALUE}.
       *******************************************************************************************************************/
      public BlockingFIFO()
      {
        // -----------------
        // Initialize object
        // -----------------
        this(Integer.MAX_VALUE);
    
      } // constructor
    
      /********************************************************************************************************************
       * The constructor creates an empty FIFO with the specified capacity.
       *
       * @param capacity_ipar The maximum number of elements the FIFO may contain.
       *******************************************************************************************************************/
      public BlockingFIFO(int capacity_ipar)
      {
        // ---------------------
        // Initialize attributes
        // ---------------------
        lock_attr = new ReentrantLock();
        not_empty_attr = lock_attr.newCondition();
        not_full_attr = lock_attr.newCondition();
        head_attr = null;
        tail_attr = null;
        capacity_attr = capacity_ipar;
        size_attr = 0;
    
      } // constructor
    
      /********************************************************************************************************************
       * This method removes all of the elements from the FIFO.
       *
       * @return The number of elements in the FIFO before it was cleared.
       *******************************************************************************************************************/
      public int clear()
      {
        // -----------------
        // Initialize result
        // -----------------
        int result;
        result = 0;
    
        // ----------
        // Clear FIFO
        // ----------
        lock_attr.lock();
        try
        {
          result = size_attr;
          head_attr = null;
          tail_attr = null;
          size_attr = 0;
          not_full_attr.signalAll();
        }
        finally
        {
          lock_attr.unlock();
        }
    
        // ----
        // Done
        // ----
        return (result);
    
      } // clear
    
      /********************************************************************************************************************
       * This method returns the number of elements in the FIFO.
       *
       * @return The number of elements in the FIFO.
       *******************************************************************************************************************/
      public int size()
      {
        // -----------
        // Return size
        // -----------
        lock_attr.lock();
        try
        {
          return (size_attr);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // size
    
      /********************************************************************************************************************
       * This method returns the number of additional elements that the FIFO can ideally accept without blocking.
       *
       * @return The remaining capacity the FIFO.
       *******************************************************************************************************************/
      public int remainingCapacity()
      {
        // -------------------------
        // Return remaining capacity
        // -------------------------
        lock_attr.lock();
        try
        {
          return (capacity_attr - size_attr);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // remainingCapacity
    
      /********************************************************************************************************************
       * This method waits for the FIFO to become empty.
       *
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for the FIFO to become
       *                              empty.
       *******************************************************************************************************************/
      public void waitEmpty()
        throws InterruptedException
      {
        // -----------------------------
        // Wait for FIFO to become empty
        // -----------------------------
        lock_attr.lock();
        try
        {
          while (size_attr > 0)
            not_full_attr.await();
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // waitEmpty
    
      /********************************************************************************************************************
       * This method waits at most the specified time for the FIFO to become empty.
       * <br>It returns <code>true</code> if the FIFO is empty and <code>false</code> otherwise.
       *
       * @param  timeout_ipar         The maximum number of milliseconds to wait for the FIFO to become empty.
       * @return                      True if and only if the FIFO is empty.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for the FIFO to become
       *                              empty.
       *******************************************************************************************************************/
      public boolean waitEmpty(long timeout_ipar)
        throws InterruptedException
      {
        // ------------------
        // Determine deadline
        // ------------------
        Date deadline;
        deadline = new Date(System.currentTimeMillis() + timeout_ipar);
    
        // -----------------------------
        // Wait for FIFO to become empty
        // -----------------------------
        lock_attr.lock();
        try
        {
          while (size_attr > 0)
          {
            if (!not_full_attr.awaitUntil(deadline))
              return (false);
          }
          return (true);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // waitEmpty
    
      /********************************************************************************************************************
       * This method waits at most the specified time for the FIFO to become empty.
       * <br>It returns <code>true</code> if the FIFO is empty and <code>false</code> otherwise.
       *
       * @param  timeout_ipar         The maximum time to wait for the FIFO to become empty.
       * @param  unit_ipar            The unit of the specified timeout.
       * @return                      True if and only if the FIFO is empty.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for the FIFO to become
       *                              empty.
       *******************************************************************************************************************/
      public boolean waitEmpty(long    timeout_ipar,
                               TimeUnit unit_ipar)
        throws InterruptedException
      {
        // -----------------------------
        // Wait for FIFO to become empty
        // -----------------------------
        return (waitEmpty(unit_ipar.toMillis(timeout_ipar)));
    
      } // waitEmpty
    
      /********************************************************************************************************************
       * This method adds the specified element at the end of the FIFO if it is possible to do so immediately without
       * exceeding the queue's capacity.
       * <br>It returns <code>true</code> upon success and <code>false</code> if this queue is full.
       *
       * @param  element_ipar The element to add to the FIFO.
       * @return              True if and only if the element was added to the FIFO.
       *******************************************************************************************************************/
      public boolean offer(E element_ipar)
      {
        // ----------------------
        // Try to add the element
        // ----------------------
        lock_attr.lock();
        try
        {
          if (capacity_attr > size_attr)
          {
            push(element_ipar);
            return (true);
          }
          else
            return (false);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // offer
    
      /********************************************************************************************************************
       * This method adds the specified element at the end of the FIFO, waiting if necessary up to the specified wait time
       * for space to become available.
       * <br>It returns <code>true</code> upon success and <code>false</code> if this queue is full.
       *
       * @param  element_ipar         The element to add to the FIFO.
       * @param  timeout_ipar         The maximum number of milliseconds to wait for space to become available.
       * @return                      True if and only if the element was added to the FIFO.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for space to become
       *                              available.
       *******************************************************************************************************************/
      public boolean offer(E    element_ipar,
                           long timeout_ipar)
        throws InterruptedException
      {
        // ------------------
        // Determine deadline
        // ------------------
        Date deadline;
        deadline = new Date(System.currentTimeMillis() + timeout_ipar);
    
        // ----------------------
        // Try to add the element
        // ----------------------
        lock_attr.lock();
        try
        {
          while (size_attr == capacity_attr)
          {
            if (!not_full_attr.awaitUntil(deadline))
              return (false);
          }
          push(element_ipar);
          return (true);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // offer
    
      /********************************************************************************************************************
       * This method adds the specified element at the end of the FIFO, waiting if necessary up to the specified wait time
       * for space to become available.
       * <br>It returns <code>true</code> upon success and <code>false</code> if this queue is full.
       *
       * @param  element_ipar         The element to add to the FIFO.
       * @param  timeout_ipar         The maximum time to wait for space to become available.
       * @param  unit_ipar            The unit of the specified timeout.
       * @return                      True if and only if the element was added to the FIFO.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for space to become
       *                              available.
       *******************************************************************************************************************/
      public boolean offer(E        element_ipar,
                           long     timeout_ipar,
                           TimeUnit unit_ipar)
        throws InterruptedException
      {
        // ----------------------------
        // Try to add specified element
        // ----------------------------
        return (offer(element_ipar, unit_ipar.toMillis(timeout_ipar)));
    
      } // offer
    
      /********************************************************************************************************************
       * This method adds the specified element at the end of the FIFO, waiting if necessary for space to become available.
       *
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for space to become
       *                              available.
       *******************************************************************************************************************/
      public void put(E element_ipar)
        throws InterruptedException
      {
        // ----------------------
        // Try to add the element
        // ----------------------
        lock_attr.lock();
        try
        {
          while (size_attr == capacity_attr)
            not_full_attr.await();
          push(element_ipar);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // put
    
      /********************************************************************************************************************
       * This method retrieves, but does not remove, the head of the FIFO, or returns <code>null</code> if the FIFO is
       * empty.
       *
       * @return The head of the FIFO, or <code>null</code> if the FIFO is empty.
       *******************************************************************************************************************/
      public E peek()
      {
        // --------------------
        // Return first element
        // --------------------
        lock_attr.lock();
        try
        {
          if (size_attr == 0)
            return (null);
          else
            return (head_attr.contents);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // peek
    
      /********************************************************************************************************************
       * This method retrieves and removes the head of the FIFO, or returns <code>null</code> if the FIFO is
       * empty.
       *
       * @return The head of the FIFO, or <code>null</code> if the FIFO is empty.
       *******************************************************************************************************************/
      public E poll()
      {
        // --------------------
        // Return first element
        // --------------------
        lock_attr.lock();
        try
        {
          if (size_attr == 0)
            return (null);
          else
            return (pop());
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // poll
    
      /********************************************************************************************************************
       * This method retrieves and removes the head of the FIFO, waiting up to the specified wait time if necessary for an
       * element to become available.
       * <br>It returns <code>null</code> if the specified waiting time elapses before an element is available.
       *
       * @param  timeout_ipar         The maximum number of milliseconds to wait for an element to become available.
       * @return                      The head of the FIFO, or <code>null</code> if the specified waiting time elapses
       *                              before an element is available.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for an element to become
       *                              available.
       *******************************************************************************************************************/
      public E poll(long timeout_ipar)
        throws InterruptedException
      {
        // ------------------
        // Determine deadline
        // ------------------
        Date deadline;
        deadline = new Date(System.currentTimeMillis() + timeout_ipar);
    
        // --------------------
        // Return first element
        // --------------------
        lock_attr.lock();
        try
        {
          while (size_attr == 0)
          {
            if (!not_empty_attr.awaitUntil(deadline))
              return (null);
          }
          return (pop());
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // poll
    
      /********************************************************************************************************************
       * This method retrieves and removes the head of the FIFO, waiting up to the specified wait time if necessary for an
       * element to become available.
       * <br>It returns <code>null</code> if the specified waiting time elapses before an element is available.
       *
       * @param  timeout_ipar         The maximum time to wait for an element to become available.
       * @param  unit_ipar            The unit of the specified timeout.
       * @return                      The head of the FIFO, or <code>null</code> if the specified waiting time elapses
       *                              before an element is available.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for an element to become
       *                              available.
       *******************************************************************************************************************/
      public E poll(long     timeout_ipar,
                    TimeUnit unit_ipar)
        throws InterruptedException
      {
        // ------------------------
        // Try to get first element
        // ------------------------
        return (poll(unit_ipar.toMillis(timeout_ipar)));
    
      } // poll
    
      /********************************************************************************************************************
       * This method retrieves and removes the head of the FIFO, waiting if necessary for an element to become available.
       *
       * @return                      The head of the FIFO.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for space to become
       *                              available.
       *******************************************************************************************************************/
      public E take()
        throws InterruptedException
      {
        // ---------------------------
        // Try to return first element
        // ---------------------------
        lock_attr.lock();
        try
        {
          while (size_attr == 0)
            not_empty_attr.await();
          return (pop());
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // take
    
      /********************************************************************************************************************
       * This class implements as node within the FIFO.
       *******************************************************************************************************************/
      private class Node
      {
        E    contents;
        Node next;
    
      } // class Node
    
      /********************************************************************************************************************
       * This method adds the specified element to the end of the FIFO.
       * <br>It sends a signal to all threads waiting for the FIFO to contain something.
       * <br>The caller should have locked the object and have made sure the list is not full.
       *******************************************************************************************************************/
      private void push(E element_ipar)
      {
        // -----------
        // Create node
        // -----------
        Node node;
        node = new Node();
        node.contents = element_ipar;
        node.next = null;
    
        // --------------
        // Add to the end
        // --------------
        if (head_attr == null)
          head_attr = node;
        else
          tail_attr.next = node;
        tail_attr = node;
    
        // ----------------------
        // We got another element
        // ----------------------
        size_attr++;
        not_empty_attr.signalAll();
    
      } // push
    
      /********************************************************************************************************************
       * This method removes the first element from the FIFO and returns it.
       * <br>It sends a signal to all threads waiting for the FIFO to have space available.
       * <br>The caller should have locked the object and have made sure the list is not empty.
       *******************************************************************************************************************/
      private E pop()
      {
        // ------------
        // Isolate node
        // ------------
        Node node;
        node = head_attr;
        head_attr = node.next;
        if (head_attr == null)
          tail_attr = null;
    
        // --------------------------
        // We removed another element
        // --------------------------
        size_attr--;
        not_full_attr.signalAll();
    
        // ----
        // Done
        // ----
        return (node.contents);
    
      } // pop
    
      /********************************************************************************************************************
       * This attribute represents the lock on the FIFO.
       *******************************************************************************************************************/
      private Lock lock_attr;
    
      /********************************************************************************************************************
       * This attribute represents the condition of the FIFO not being empty.
       *******************************************************************************************************************/
      private Condition not_empty_attr;
    
      /********************************************************************************************************************
       * This attribute represents the condition of the FIFO not being full.
       *******************************************************************************************************************/
      private Condition not_full_attr;
    
      /********************************************************************************************************************
       * This attribute represents the first element of the FIFO.
       *******************************************************************************************************************/
      private Node head_attr;
    
      /********************************************************************************************************************
       * This attribute represents the last element of the FIFO.
       *******************************************************************************************************************/
      private Node tail_attr;
    
      /********************************************************************************************************************
       * This attribute represents the capacity of the FIFO.
       *******************************************************************************************************************/
      private int capacity_attr;
    
      /********************************************************************************************************************
       * This attribute represents the size of the FIFO.
       *******************************************************************************************************************/
      private int size_attr;
    
    } // class BlockingFIFO
    

    显然,您可以调用
    peek
    ,直到它返回
    null
    。阻止是什么让这成为一个不可接受的解决方案?编辑的答案是否定的。请注意,正如我在回答中所写,您的用例非常独特。。。确保你真的需要做你要求的事情。你没有说明你为什么需要这样的行为。@Joãof ernandes:我现在并不严格需要它,只是出于好奇。我喜欢阅读关于编程问题的观点。这是一个很好的论点:)让我们等待更多的答案,看看是否有人知道我们不知道的事情。嗨@niculare,这段代码会导致死锁吗?两个代码段锁定在同一个对象
    队列
    ,这会阻止生产者和消费者同时进行工作。因此,当生产者等待队列为空时,队列可能永远不会为空。@liuyaodong不,请阅读
    Object.wait()的Javadoc。它释放锁,直到另一个线程调用
    notify
    。它甚至明确地说“当前线程必须拥有这个对象的监视器”。这是如何工作的?假设消费者首先运行并在queue.get()上被阻止,因为队列中还没有项目。现在生产者无法生产,因为它无法获得锁。
    BlockingQueue
    没有
    get
    方法。你的意思是
    poll
    还是
    take
    ?我的意思是
    take
    ,因为
    poll
    在这种情况下没有任何效果
        Collection<Item> queue = ...
        Collection<Callable<Result>> tasks = new ArrayList<Callable<Result>>();
    
        for (Item item : queue) {
            tasks.add(new Callable<Result>() {
    
                @Override
                public Result call() throws Exception {
                    // process the item ...
    
                    return result;
                }
            });
        }
    
        // look at the results, add timeout for invokeAll if necessary
        List<Future<Result>> results = executorService.invokeAll(tasks);
    
        // done
    
    /**********************************************************************************************************************
     * Import specifications
     *********************************************************************************************************************/
    import java.util.Date;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.*;
    
    /**********************************************************************************************************************
     * This class implements a completely reentrant FIFO.
     *********************************************************************************************************************/
    public class BlockingFIFO<E>
    {
      /********************************************************************************************************************
       * The constructor creates an empty FIFO with a capacity of {@link Integer#MAX_VALUE}.
       *******************************************************************************************************************/
      public BlockingFIFO()
      {
        // -----------------
        // Initialize object
        // -----------------
        this(Integer.MAX_VALUE);
    
      } // constructor
    
      /********************************************************************************************************************
       * The constructor creates an empty FIFO with the specified capacity.
       *
       * @param capacity_ipar The maximum number of elements the FIFO may contain.
       *******************************************************************************************************************/
      public BlockingFIFO(int capacity_ipar)
      {
        // ---------------------
        // Initialize attributes
        // ---------------------
        lock_attr = new ReentrantLock();
        not_empty_attr = lock_attr.newCondition();
        not_full_attr = lock_attr.newCondition();
        head_attr = null;
        tail_attr = null;
        capacity_attr = capacity_ipar;
        size_attr = 0;
    
      } // constructor
    
      /********************************************************************************************************************
       * This method removes all of the elements from the FIFO.
       *
       * @return The number of elements in the FIFO before it was cleared.
       *******************************************************************************************************************/
      public int clear()
      {
        // -----------------
        // Initialize result
        // -----------------
        int result;
        result = 0;
    
        // ----------
        // Clear FIFO
        // ----------
        lock_attr.lock();
        try
        {
          result = size_attr;
          head_attr = null;
          tail_attr = null;
          size_attr = 0;
          not_full_attr.signalAll();
        }
        finally
        {
          lock_attr.unlock();
        }
    
        // ----
        // Done
        // ----
        return (result);
    
      } // clear
    
      /********************************************************************************************************************
       * This method returns the number of elements in the FIFO.
       *
       * @return The number of elements in the FIFO.
       *******************************************************************************************************************/
      public int size()
      {
        // -----------
        // Return size
        // -----------
        lock_attr.lock();
        try
        {
          return (size_attr);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // size
    
      /********************************************************************************************************************
       * This method returns the number of additional elements that the FIFO can ideally accept without blocking.
       *
       * @return The remaining capacity the FIFO.
       *******************************************************************************************************************/
      public int remainingCapacity()
      {
        // -------------------------
        // Return remaining capacity
        // -------------------------
        lock_attr.lock();
        try
        {
          return (capacity_attr - size_attr);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // remainingCapacity
    
      /********************************************************************************************************************
       * This method waits for the FIFO to become empty.
       *
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for the FIFO to become
       *                              empty.
       *******************************************************************************************************************/
      public void waitEmpty()
        throws InterruptedException
      {
        // -----------------------------
        // Wait for FIFO to become empty
        // -----------------------------
        lock_attr.lock();
        try
        {
          while (size_attr > 0)
            not_full_attr.await();
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // waitEmpty
    
      /********************************************************************************************************************
       * This method waits at most the specified time for the FIFO to become empty.
       * <br>It returns <code>true</code> if the FIFO is empty and <code>false</code> otherwise.
       *
       * @param  timeout_ipar         The maximum number of milliseconds to wait for the FIFO to become empty.
       * @return                      True if and only if the FIFO is empty.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for the FIFO to become
       *                              empty.
       *******************************************************************************************************************/
      public boolean waitEmpty(long timeout_ipar)
        throws InterruptedException
      {
        // ------------------
        // Determine deadline
        // ------------------
        Date deadline;
        deadline = new Date(System.currentTimeMillis() + timeout_ipar);
    
        // -----------------------------
        // Wait for FIFO to become empty
        // -----------------------------
        lock_attr.lock();
        try
        {
          while (size_attr > 0)
          {
            if (!not_full_attr.awaitUntil(deadline))
              return (false);
          }
          return (true);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // waitEmpty
    
      /********************************************************************************************************************
       * This method waits at most the specified time for the FIFO to become empty.
       * <br>It returns <code>true</code> if the FIFO is empty and <code>false</code> otherwise.
       *
       * @param  timeout_ipar         The maximum time to wait for the FIFO to become empty.
       * @param  unit_ipar            The unit of the specified timeout.
       * @return                      True if and only if the FIFO is empty.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for the FIFO to become
       *                              empty.
       *******************************************************************************************************************/
      public boolean waitEmpty(long    timeout_ipar,
                               TimeUnit unit_ipar)
        throws InterruptedException
      {
        // -----------------------------
        // Wait for FIFO to become empty
        // -----------------------------
        return (waitEmpty(unit_ipar.toMillis(timeout_ipar)));
    
      } // waitEmpty
    
      /********************************************************************************************************************
       * This method adds the specified element at the end of the FIFO if it is possible to do so immediately without
       * exceeding the queue's capacity.
       * <br>It returns <code>true</code> upon success and <code>false</code> if this queue is full.
       *
       * @param  element_ipar The element to add to the FIFO.
       * @return              True if and only if the element was added to the FIFO.
       *******************************************************************************************************************/
      public boolean offer(E element_ipar)
      {
        // ----------------------
        // Try to add the element
        // ----------------------
        lock_attr.lock();
        try
        {
          if (capacity_attr > size_attr)
          {
            push(element_ipar);
            return (true);
          }
          else
            return (false);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // offer
    
      /********************************************************************************************************************
       * This method adds the specified element at the end of the FIFO, waiting if necessary up to the specified wait time
       * for space to become available.
       * <br>It returns <code>true</code> upon success and <code>false</code> if this queue is full.
       *
       * @param  element_ipar         The element to add to the FIFO.
       * @param  timeout_ipar         The maximum number of milliseconds to wait for space to become available.
       * @return                      True if and only if the element was added to the FIFO.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for space to become
       *                              available.
       *******************************************************************************************************************/
      public boolean offer(E    element_ipar,
                           long timeout_ipar)
        throws InterruptedException
      {
        // ------------------
        // Determine deadline
        // ------------------
        Date deadline;
        deadline = new Date(System.currentTimeMillis() + timeout_ipar);
    
        // ----------------------
        // Try to add the element
        // ----------------------
        lock_attr.lock();
        try
        {
          while (size_attr == capacity_attr)
          {
            if (!not_full_attr.awaitUntil(deadline))
              return (false);
          }
          push(element_ipar);
          return (true);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // offer
    
      /********************************************************************************************************************
       * This method adds the specified element at the end of the FIFO, waiting if necessary up to the specified wait time
       * for space to become available.
       * <br>It returns <code>true</code> upon success and <code>false</code> if this queue is full.
       *
       * @param  element_ipar         The element to add to the FIFO.
       * @param  timeout_ipar         The maximum time to wait for space to become available.
       * @param  unit_ipar            The unit of the specified timeout.
       * @return                      True if and only if the element was added to the FIFO.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for space to become
       *                              available.
       *******************************************************************************************************************/
      public boolean offer(E        element_ipar,
                           long     timeout_ipar,
                           TimeUnit unit_ipar)
        throws InterruptedException
      {
        // ----------------------------
        // Try to add specified element
        // ----------------------------
        return (offer(element_ipar, unit_ipar.toMillis(timeout_ipar)));
    
      } // offer
    
      /********************************************************************************************************************
       * This method adds the specified element at the end of the FIFO, waiting if necessary for space to become available.
       *
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for space to become
       *                              available.
       *******************************************************************************************************************/
      public void put(E element_ipar)
        throws InterruptedException
      {
        // ----------------------
        // Try to add the element
        // ----------------------
        lock_attr.lock();
        try
        {
          while (size_attr == capacity_attr)
            not_full_attr.await();
          push(element_ipar);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // put
    
      /********************************************************************************************************************
       * This method retrieves, but does not remove, the head of the FIFO, or returns <code>null</code> if the FIFO is
       * empty.
       *
       * @return The head of the FIFO, or <code>null</code> if the FIFO is empty.
       *******************************************************************************************************************/
      public E peek()
      {
        // --------------------
        // Return first element
        // --------------------
        lock_attr.lock();
        try
        {
          if (size_attr == 0)
            return (null);
          else
            return (head_attr.contents);
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // peek
    
      /********************************************************************************************************************
       * This method retrieves and removes the head of the FIFO, or returns <code>null</code> if the FIFO is
       * empty.
       *
       * @return The head of the FIFO, or <code>null</code> if the FIFO is empty.
       *******************************************************************************************************************/
      public E poll()
      {
        // --------------------
        // Return first element
        // --------------------
        lock_attr.lock();
        try
        {
          if (size_attr == 0)
            return (null);
          else
            return (pop());
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // poll
    
      /********************************************************************************************************************
       * This method retrieves and removes the head of the FIFO, waiting up to the specified wait time if necessary for an
       * element to become available.
       * <br>It returns <code>null</code> if the specified waiting time elapses before an element is available.
       *
       * @param  timeout_ipar         The maximum number of milliseconds to wait for an element to become available.
       * @return                      The head of the FIFO, or <code>null</code> if the specified waiting time elapses
       *                              before an element is available.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for an element to become
       *                              available.
       *******************************************************************************************************************/
      public E poll(long timeout_ipar)
        throws InterruptedException
      {
        // ------------------
        // Determine deadline
        // ------------------
        Date deadline;
        deadline = new Date(System.currentTimeMillis() + timeout_ipar);
    
        // --------------------
        // Return first element
        // --------------------
        lock_attr.lock();
        try
        {
          while (size_attr == 0)
          {
            if (!not_empty_attr.awaitUntil(deadline))
              return (null);
          }
          return (pop());
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // poll
    
      /********************************************************************************************************************
       * This method retrieves and removes the head of the FIFO, waiting up to the specified wait time if necessary for an
       * element to become available.
       * <br>It returns <code>null</code> if the specified waiting time elapses before an element is available.
       *
       * @param  timeout_ipar         The maximum time to wait for an element to become available.
       * @param  unit_ipar            The unit of the specified timeout.
       * @return                      The head of the FIFO, or <code>null</code> if the specified waiting time elapses
       *                              before an element is available.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for an element to become
       *                              available.
       *******************************************************************************************************************/
      public E poll(long     timeout_ipar,
                    TimeUnit unit_ipar)
        throws InterruptedException
      {
        // ------------------------
        // Try to get first element
        // ------------------------
        return (poll(unit_ipar.toMillis(timeout_ipar)));
    
      } // poll
    
      /********************************************************************************************************************
       * This method retrieves and removes the head of the FIFO, waiting if necessary for an element to become available.
       *
       * @return                      The head of the FIFO.
       * @throws InterruptedException Thrown when the current thread got interrupted while waiting for space to become
       *                              available.
       *******************************************************************************************************************/
      public E take()
        throws InterruptedException
      {
        // ---------------------------
        // Try to return first element
        // ---------------------------
        lock_attr.lock();
        try
        {
          while (size_attr == 0)
            not_empty_attr.await();
          return (pop());
        }
        finally
        {
          lock_attr.unlock();
        }
    
      } // take
    
      /********************************************************************************************************************
       * This class implements as node within the FIFO.
       *******************************************************************************************************************/
      private class Node
      {
        E    contents;
        Node next;
    
      } // class Node
    
      /********************************************************************************************************************
       * This method adds the specified element to the end of the FIFO.
       * <br>It sends a signal to all threads waiting for the FIFO to contain something.
       * <br>The caller should have locked the object and have made sure the list is not full.
       *******************************************************************************************************************/
      private void push(E element_ipar)
      {
        // -----------
        // Create node
        // -----------
        Node node;
        node = new Node();
        node.contents = element_ipar;
        node.next = null;
    
        // --------------
        // Add to the end
        // --------------
        if (head_attr == null)
          head_attr = node;
        else
          tail_attr.next = node;
        tail_attr = node;
    
        // ----------------------
        // We got another element
        // ----------------------
        size_attr++;
        not_empty_attr.signalAll();
    
      } // push
    
      /********************************************************************************************************************
       * This method removes the first element from the FIFO and returns it.
       * <br>It sends a signal to all threads waiting for the FIFO to have space available.
       * <br>The caller should have locked the object and have made sure the list is not empty.
       *******************************************************************************************************************/
      private E pop()
      {
        // ------------
        // Isolate node
        // ------------
        Node node;
        node = head_attr;
        head_attr = node.next;
        if (head_attr == null)
          tail_attr = null;
    
        // --------------------------
        // We removed another element
        // --------------------------
        size_attr--;
        not_full_attr.signalAll();
    
        // ----
        // Done
        // ----
        return (node.contents);
    
      } // pop
    
      /********************************************************************************************************************
       * This attribute represents the lock on the FIFO.
       *******************************************************************************************************************/
      private Lock lock_attr;
    
      /********************************************************************************************************************
       * This attribute represents the condition of the FIFO not being empty.
       *******************************************************************************************************************/
      private Condition not_empty_attr;
    
      /********************************************************************************************************************
       * This attribute represents the condition of the FIFO not being full.
       *******************************************************************************************************************/
      private Condition not_full_attr;
    
      /********************************************************************************************************************
       * This attribute represents the first element of the FIFO.
       *******************************************************************************************************************/
      private Node head_attr;
    
      /********************************************************************************************************************
       * This attribute represents the last element of the FIFO.
       *******************************************************************************************************************/
      private Node tail_attr;
    
      /********************************************************************************************************************
       * This attribute represents the capacity of the FIFO.
       *******************************************************************************************************************/
      private int capacity_attr;
    
      /********************************************************************************************************************
       * This attribute represents the size of the FIFO.
       *******************************************************************************************************************/
      private int size_attr;
    
    } // class BlockingFIFO