code: private int read(byte[] bytes, int offset, int length, Duration receiveTimeout)
              throws InterruptedException, TTransportException
      {
          long timeRemaining = receiveTimeout.roundTo(TimeUnit.NANOSECONDS);
          lock.lock();
          try {
              while (!closed) {
                  int bytesAvailable = readBuffer.readableBytes();
                  if (bytesAvailable > 0) {
                      int begin = readBuffer.readerIndex();
                      readBuffer.readBytes(bytes, offset, Math.min(bytesAvailable, length));
                      int end = readBuffer.readerIndex();
                      return end - begin;
                  }
                  if (timeRemaining <= 0) {
                      break;
                  }
                  timeRemaining = condition.awaitNanos(timeRemaining);
                  if (exception != null) {
                      try {
                          throw new TTransportException(exception);
                      }
                      finally {
                          exception = null;
                          closed = true;
                          close();
                      }
                  }
              }
              if (closed) {
                  throw new TTransportException("channel closed !");
              }
          }
          finally {
              lock.unlock();
          }
          throw new TTransportException(String.format("receive timeout, %d ms has elapsed", receiveTimeout.toMillis()));
      }
docs: yeah, mimicking sync with async is just horrible