code: public List<E> getBatchBlocking(long timeoutMillis) throws InterruptedException {
  		if (timeoutMillis == 0L) {
  			// wait forever case
  			return getBatchBlocking();
  		} else if (timeoutMillis < 0L) {
  			throw new IllegalArgumentException("invalid timeout");
  		}
  
  		final long deadline = System.nanoTime() + timeoutMillis * 1_000_000L;
  
  		lock.lock();
  		try {
  			while (open && elements.isEmpty() && timeoutMillis > 0) {
  				nonEmpty.await(timeoutMillis, TimeUnit.MILLISECONDS);
  				timeoutMillis = (deadline - System.nanoTime()) / 1_000_000L;
  			}
  
  			if (!open) {
  				throw new IllegalStateException("queue is closed");
  			}
  			else if (elements.isEmpty()) {
  				return Collections.emptyList();
  			}
  			else {
  				ArrayList<E> result = new ArrayList<>(elements);
  				elements.clear();
  				return result;
  			}
  		} finally {
  			lock.unlock();
  		}
  	}
docs: Gets all the elements found in the list, or blocks until at least one element
  was added. This method is similar as {@link #getBatchBlocking()}, but takes
  a number of milliseconds that the method will maximally wait before returning.
  
  <p>This method never returns null, but an empty list, if the queue is empty when
  the method is called and the request times out before an element was added.
  
  <p>The method throws an {@code IllegalStateException} if the queue is closed.
  Checking whether the queue is open and removing the next element is one atomic operation.
  
  @param timeoutMillis The number of milliseconds to wait, at most.
  @return A list with all elements in the queue, possible an empty list.
  
  @throws IllegalStateException Thrown, if the queue is closed.
  @throws InterruptedException Throw, if the thread is interrupted while waiting for an
  element to be added.