private void closeAsync(CompletableFuture<?> future) {
        if (!eventLoop.inEventLoop()) {
            eventLoop.execute(() -> closeAsync(future));
            return;
        }

        // NB: Make a copy first, because close() will trigger the closeFuture listener
        //     which mutates allChannels back, causing ConcurrentModificationException.
        final Channel[] allChannels = this.allChannels.keySet().toArray(EMPTY_CHANNELS);
        final int numAllChannels = allChannels.length;
        if (numAllChannels == 0) {
            future.complete(null);
            return;
        }

        // Complete the given future when all channels are closed.
        final ChannelFutureListener listener = new ChannelFutureListener() {
            private int numRemainingChannels = numAllChannels;

            @Override
            public void operationComplete(ChannelFuture unused) throws Exception {
                if (--numRemainingChannels <= 0) {
                    future.complete(null);
                }
            }
        };

        for (Channel ch : allChannels) {
            ch.close().addListener(listener);
        }
    }
Adds a {@link Channel} to this pool.
core/src/main/java/com/linecorp/armeria/client/HttpChannelPool.java