private boolean advanceBuffer() throws IOException {
    int nextActiveBuffer = (activeBuffer + 1) % counts.length;
    if (counts[nextActiveBuffer] == 0) {
      if (exhausted) {
        rethrowException();
        return false;
      }
      myBufferFiller.fillReserve();

      synchronized (lockObject) {
        while (counts[nextActiveBuffer] == 0 && !exhausted) {
          try {
            lockObject.wait();
          } catch (InterruptedException e) {
            IOException ioe = new InterruptedIOException();
            ioe.initCause(e);
            throw ioe;
          }
        }
      }
      if (counts[nextActiveBuffer] == 0 && exhausted) {
        rethrowException();
        return false;
      }
    }
    counts[activeBuffer] = 0;
    activeBuffer = nextActiveBuffer;
    pos = 0;
    myBufferFiller.fillReserve();
    return true;
  }
  @Override
  public synchronized long skip(long n) throws IOException {
    checkClosed();
    if (n <= 0) {
      return 0;
    }
    long skipped = 0;
    int thisBuffer = activeBuffer;
    do {
      int remaining = counts[thisBuffer] - pos;
      if (remaining >= n) {
        pos += n;
        skipped += n;
        break;
      }
      pos = 0;
      n -= remaining;
      skipped += remaining;
      thisBuffer = (thisBuffer + 1) % counts.length;
    } while (thisBuffer != activeBuffer);

    activeBuffer = thisBuffer;
    myBufferFiller.fillReserve();
    return skipped;
  }
 @Override
 public void close() throws IOException {
   if (buffers == null) {
     return;
   }
   myBufferFiller.close();
   buffers = null;
   counts = null;
 }