code: public boolean offer(E e, long timeout, TimeUnit unit)
          throws InterruptedException {
  
          if (e == null) throw new NullPointerException();
          long nanos = unit.toNanos(timeout);
          int c = -1;
          final ReentrantLock putLock = this.putLock;
          final AtomicInteger count = this.count;
          putLock.lockInterruptibly();
          try {
              while (count.get() == capacity) {
                  if (nanos <= 0L)
                      return false;
                  nanos = notFull.awaitNanos(nanos);
              }
              enqueue(new Node<E>(e));
              c = count.getAndIncrement();
              if (c + 1 < capacity)
                  notFull.signal();
          } finally {
              putLock.unlock();
          }
          if (c == 0)
              signalNotEmpty();
          return true;
      }
docs: Inserts the specified element at the tail of this queue, waiting if
  necessary up to the specified wait time for space to become available.
  
  @return {@code true} if successful, or {@code false} if
  the specified waiting time elapses before space is available
  @throws InterruptedException {@inheritDoc}
  @throws NullPointerException {@inheritDoc}