public void batchAckMessageAsync(
        final String addr,
        final long timeOut,
        final AckCallback ackCallback,
        final String topic,
        final String consumerGroup,
        final List<String> extraInfoList
    ) throws RemotingException, MQBrokerException, InterruptedException {
        String brokerName = null;
        Map<String, BatchAck> batchAckMap = new HashMap<>();
        for (String extraInfo : extraInfoList) {
            String[] extraInfoData = ExtraInfoUtil.split(extraInfo);
            if (brokerName == null) {
                brokerName = ExtraInfoUtil.getBrokerName(extraInfoData);
            }
            String mergeKey = ExtraInfoUtil.getRetry(extraInfoData) + "@" +
                ExtraInfoUtil.getQueueId(extraInfoData) + "@" +
                ExtraInfoUtil.getCkQueueOffset(extraInfoData) + "@" +
                ExtraInfoUtil.getPopTime(extraInfoData);
            BatchAck bAck = batchAckMap.computeIfAbsent(mergeKey, k -> {
                BatchAck newBatchAck = new BatchAck();
                newBatchAck.setConsumerGroup(consumerGroup);
                newBatchAck.setTopic(topic);
                newBatchAck.setRetry(ExtraInfoUtil.getRetry(extraInfoData));
                newBatchAck.setStartOffset(ExtraInfoUtil.getCkQueueOffset(extraInfoData));
                newBatchAck.setQueueId(ExtraInfoUtil.getQueueId(extraInfoData));
                newBatchAck.setReviveQueueId(ExtraInfoUtil.getReviveQid(extraInfoData));
                newBatchAck.setPopTime(ExtraInfoUtil.getPopTime(extraInfoData));
                newBatchAck.setInvisibleTime(ExtraInfoUtil.getInvisibleTime(extraInfoData));
                newBatchAck.setBitSet(new BitSet());
                return newBatchAck;
            });
            bAck.getBitSet().set((int) (ExtraInfoUtil.getQueueOffset(extraInfoData) - ExtraInfoUtil.getCkQueueOffset(extraInfoData)));
        }

        BatchAckMessageRequestBody requestBody = new BatchAckMessageRequestBody();
        requestBody.setBrokerName(brokerName);
        requestBody.setAcks(new ArrayList<>(batchAckMap.values()));
        batchAckMessageAsync(addr, timeOut, ackCallback, requestBody);
    }
@Test
    public void testBatchAckMessageAsync() throws MQBrokerException, RemotingException, InterruptedException {
        AckCallback callback = mock(AckCallback.class);
        List<String> extraInfoList = new ArrayList<>();
        extraInfoList.add(String.format("%s %s %s %s %s %s %d %d", "1", "2", "3", "4", "5", brokerName, 7, 8));
        mqClientAPI.batchAckMessageAsync(defaultBrokerAddr, defaultTimeout, callback, defaultTopic, "", extraInfoList);
    }