private void finishDoStop(CompletableFuture<Void> future) {
            serverChannels.clear();

            final Builder<ShutdownSupport> builder = ImmutableList.builder();
            builder.addAll(config.delegate().shutdownSupports());
            for (VirtualHost virtualHost : config.virtualHosts()) {
                builder.addAll(virtualHost.shutdownSupports());
            }
            for (ServiceConfig serviceConfig : config.serviceConfigs()) {
                builder.addAll(serviceConfig.shutdownSupports());
            }

            CompletableFuture.runAsync(() -> {
                // ShutdownSupport may be blocking so run the entire block inside the startStopExecutor
                CompletableFutures.successfulAsList(builder.build()
                                                           .stream()
                                                           .map(ShutdownSupport::shutdown)
                                                           .collect(toImmutableList()), cause -> null)
                                  .thenRunAsync(() -> future.complete(null), config.startStopExecutor());
            }, config.startStopExecutor());
        }
Closes all channels and terminates all event loops.
<ol>
  <li>Closes all server channels so that we don't accept any more incoming connections.</li>
  <li>Closes all accepted channels.</li>
  <li>Shuts down the worker group if necessary.</li>
  <li>Shuts down the boss groups.</li>
</ol>
Note that we terminate the boss groups lastly so that the JVM does not terminate itself
even if other threads are daemon, because boss group threads are always non-daemon.
core/src/main/java/com/linecorp/armeria/server/Server.java