private void shutdownServer() {
    executorService.shutdown();

    long msLeftToWait = serverOptions.stopTimeoutUnit.toMillis(serverOptions.stopTimeoutVal);
    long timeMillis = EnvironmentEdgeManager.currentTime();

    LOG
      .info("Waiting for up to " + msLeftToWait + " ms to finish processing" + " pending requests");
    boolean interrupted = false;
    while (msLeftToWait >= 0) {
      try {
        executorService.awaitTermination(msLeftToWait, TimeUnit.MILLISECONDS);
        break;
      } catch (InterruptedException ix) {
        long timePassed = EnvironmentEdgeManager.currentTime() - timeMillis;
        msLeftToWait -= timePassed;
        timeMillis += timePassed;
        interrupted = true;
      }
    }

    LOG.info("Interrupting all worker threads and waiting for " + TIME_TO_WAIT_AFTER_SHUTDOWN_MS
      + " ms longer");

    // This will interrupt all the threads, even those running a task.
    executorService.shutdownNow();
    Threads.sleepWithoutInterrupt(TIME_TO_WAIT_AFTER_SHUTDOWN_MS);

    // Preserve the interrupted status.
    if (interrupted) {
      Thread.currentThread().interrupt();
    }
    LOG.info("Thrift server shutdown complete");
  }
Loop until {@link ExecutorService#awaitTermination} finally does return without an interrupted
exception. If we don't do this, then we'll shut down prematurely. We want to let the executor
service clear its task queue, closing client sockets appropriately.
hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/TBoundedThreadPoolServer.java