class AbstractGrpcClient {

    private static Map<String, ManagedChannel[]> channels = new ConcurrentHashMap<>();
    private static int n = 5;
    private static int concurrency = 1 << n;
    private static AtomicLong counter = new AtomicLong(0);
    private static long limit = Long.MAX_VALUE >> 1;
    private static HgStoreClientConfig config = HgStoreClientConfig.of();
    private Map<String, HgPair<ManagedChannel, AbstractBlockingStub>[]> blockingStubs =
            new ConcurrentHashMap<>();
    private Map<String, HgPair<ManagedChannel, AbstractAsyncStub>[]> asyncStubs =
            new ConcurrentHashMap<>();
    private ThreadPoolExecutor executor;

    {
        executor = ExecutorPool.createExecutor("common", 60, concurrency, concurrency);
    }

    public AbstractGrpcClient() {

    }

    public ManagedChannel[] getChannels(String target) {
        ManagedChannel[] tc;
        if ((tc = channels.get(target)) == null) {
            synchronized (channels) {
                if ((tc = channels.get(target)) == null) {
                    try {
                        ManagedChannel[] value = new ManagedChannel[concurrency];
                        CountDownLatch latch = new CountDownLatch(concurrency);
                        for (int i = 0; i < concurrency; i++) {
                            int fi = i;
                            executor.execute(() -> {
                                try {
                                    value[fi] = getManagedChannel(target);
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                } finally {
                                    latch.countDown();
                                }
                            });
                        }
                        latch.await();
                        channels.put(target, tc = value);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return tc;
    }

    public abstract AbstractBlockingStub getBlockingStub(ManagedChannel channel);

    public AbstractBlockingStub getBlockingStub(String target) {
        ManagedChannel[] channels = getChannels(target);
        HgPair<ManagedChannel, AbstractBlockingStub>[] pairs = blockingStubs.get(target);
        long l = counter.getAndIncrement();
        if (l >= limit) {
            counter.set(0);
        }
        int index = (int) (l & (concurrency - 1));
        if (pairs == null) {
            synchronized (blockingStubs) {
                pairs = blockingStubs.get(target);
                if (pairs == null) {
                    HgPair<ManagedChannel, AbstractBlockingStub>[] value = new HgPair[concurrency];
                    IntStream.range(0, concurrency).forEach(i -> {
                        ManagedChannel channel = channels[index];
                        AbstractBlockingStub stub = getBlockingStub(channel);
                        value[i] = new HgPair<>(channel, stub);
                        // log.info("create channel for {}",target);
                    });
                    blockingStubs.put(target, value);
                    AbstractBlockingStub stub = value[index].getValue();
                    return (AbstractBlockingStub) setBlockingStubOption(stub);
                }
            }
        }
        return (AbstractBlockingStub) setBlockingStubOption(pairs[index].getValue());
    }

    private AbstractStub setBlockingStubOption(AbstractBlockingStub stub) {
        return stub.withDeadlineAfter(config.getGrpcTimeoutSeconds(), TimeUnit.SECONDS)
                   .withMaxInboundMessageSize(
                           config.getGrpcMaxInboundMessageSize())
                   .withMaxOutboundMessageSize(
                           config.getGrpcMaxOutboundMessageSize());
    }

    public AbstractAsyncStub getAsyncStub(ManagedChannel channel) {
        return null;
    }

    public AbstractAsyncStub getAsyncStub(String target) {<FILL_FUNCTION_BODY>}

    private AbstractStub setStubOption(AbstractStub value) {
        return value.withMaxInboundMessageSize(
                            config.getGrpcMaxInboundMessageSize())
                    .withMaxOutboundMessageSize(
                            config.getGrpcMaxOutboundMessageSize());
    }

    private ManagedChannel getManagedChannel(String target) {
        return ManagedChannelBuilder.forTarget(target).usePlaintext().build();
    }

}

        ManagedChannel[] channels = getChannels(target);
        HgPair<ManagedChannel, AbstractAsyncStub>[] pairs = asyncStubs.get(target);
        long l = counter.getAndIncrement();
        if (l >= limit) {
            counter.set(0);
        }
        int index = (int) (l & (concurrency - 1));
        if (pairs == null) {
            synchronized (asyncStubs) {
                pairs = asyncStubs.get(target);
                if (pairs == null) {
                    HgPair<ManagedChannel, AbstractAsyncStub>[] value = new HgPair[concurrency];
                    IntStream.range(0, concurrency).parallel().forEach(i -> {
                        ManagedChannel channel = channels[index];
                        AbstractAsyncStub stub = getAsyncStub(channel);
                        // stub.withMaxInboundMessageSize(config.getGrpcMaxInboundMessageSize())
                        //    .withMaxOutboundMessageSize(config.getGrpcMaxOutboundMessageSize());
                        value[i] = new HgPair<>(channel, stub);
                        // log.info("create channel for {}",target);
                    });
                    asyncStubs.put(target, value);
                    AbstractAsyncStub stub =
                            (AbstractAsyncStub) setStubOption(value[index].getValue());
                    return stub;
                }
            }
        }
        return (AbstractAsyncStub) setStubOption(pairs[index].getValue());

    
<no_super_class>