@Override
        protected CompletionStage<Void> doStop(@Nullable Void arg) {
            final CompletableFuture<Void> future = new CompletableFuture<>();
            final GracefulShutdownSupport gracefulShutdownSupport = this.gracefulShutdownSupport;
            if (gracefulShutdownSupport == null ||
                gracefulShutdownSupport.completedQuietPeriod()) {
                doStop(future, null);
                return future;
            }

            // Create a single-use thread dedicated for monitoring graceful shutdown status.
            final ScheduledExecutorService gracefulShutdownExecutor =
                    Executors.newSingleThreadScheduledExecutor(
                            r -> new Thread(r, "armeria-shutdown-0x" + Integer.toHexString(hashCode())));

            // Check every 100 ms for the server to have completed processing requests.
            final ScheduledFuture<?> quietPeriodFuture = gracefulShutdownExecutor.scheduleAtFixedRate(() -> {
                if (gracefulShutdownSupport.completedQuietPeriod()) {
                    doStop(future, gracefulShutdownExecutor);
                }
            }, 0, 100, TimeUnit.MILLISECONDS);

            // Make sure the event loop stops after the timeout, regardless of what
            // the GracefulShutdownSupport says.
            try {
                gracefulShutdownExecutor.schedule(() -> {
                    quietPeriodFuture.cancel(false);
                    doStop(future, gracefulShutdownExecutor);
                }, config.gracefulShutdown().timeout().toMillis(), TimeUnit.MILLISECONDS);
            } catch (RejectedExecutionException e) {
                // Can be rejected if quiet period is complete already.
            }

            return future;
        }
Registers a JVM shutdown hook that closes this {@link Server} when the current JVM terminates.

@param whenClosing the {@link Runnable} will be run before closing this {@link Server}
core/src/main/java/com/linecorp/armeria/server/Server.java