Java 并发轮询下游依赖项,并等待所有依赖项都成功

Java 并发轮询下游依赖项,并等待所有依赖项都成功,java,concurrency,Java,Concurrency,我试图编写一个简单的函数,它可以长时间轮询多条消息到下游依赖项,而不会耗尽它,并且只在所有消息成功时才存在 我想出了一种方法,将每个消息轮询包装成一个callable,并使用ExecutorService提交一个callable列表 public void poll(final List<Long> messageIdList) { ExecutorService executorService = Executors.newFixedThreadPool(

我试图编写一个简单的函数,它可以长时间轮询多条消息到下游依赖项,而不会耗尽它,并且只在所有消息成功时才存在

我想出了一种方法,将每个消息轮询包装成一个callable,并使用ExecutorService提交一个callable列表


    public void poll(final List<Long> messageIdList) {
        ExecutorService executorService = Executors.newFixedThreadPool(messageIdList.size());
        List<MessageStatusCallable> callables = messageIdList.stream()
                .map(messageId -> new MessageStatusCallable(messageId)).collect(Collectors.toList());
        boolean allSuccess = false;
        try {
            allSuccess = executorService.invokeAll(callables).stream().allMatch(success -> {
                try {
                    return success.get().equals(Boolean.TRUE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return false;
                } catch (ExecutionException e) {
                    e.printStackTrace();
                    return false;
                }
            });
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private class MessageStatusCallable implements Callable<Boolean> {
        private Long messageId;
        public MessageStatusCallable(Long messageId) {
            this.messageId = messageId;
        }

        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        @Override
        public Boolean call() throws Exception {
            String messageStatus = downstreamService.getMessageStatus(messageId);
            while(messageStatus == null || !messageStatus.equals( STATUS_VALUE_SUCCEEDED) {
                messageStatus = messageLogToControlServer.getMessageStatus(messageId);
                Thread.sleep(TimeUnit.MICROSECONDS.toMillis(100));
            }
            LOG.info("Message: " + messageId + " Succeded");
            return true;
        }
    }

public void poll(最终列表messageIdList){
ExecutorService ExecutorService=Executors.newFixedThreadPool(messageIdList.size());
List callables=messageIdList.stream()
.map(messageId->newmessagestatuscallable(messageId)).collect(Collectors.toList());
布尔allSuccess=false;
试一试{
allSuccess=executorService.invokeAll(callables).stream().allMatch(成功->{
试一试{
返回success.get().equals(Boolean.TRUE);
}捕捉(中断异常e){
e、 printStackTrace();
返回false;
}捕获(执行例外){
e、 printStackTrace();
返回false;
}
});
}捕捉(中断异常e){
e、 printStackTrace();
}
}
私有类MessageStatusCallable实现了Callable{
私有长消息ID;
public MessageStatusCallable(长messageId){
this.messageId=messageId;
}
/**
*计算结果,如果无法执行此操作,则引发异常。
*
*@返回计算结果
*@如果无法计算结果,则引发异常
*/
@凌驾
公共布尔调用()引发异常{
字符串messageStatus=downstreamService.getMessageStatus(messageId);
while(messageStatus==null | |!messageStatus.equals(STATUS_VALUE_successed){
messageStatus=messageLogToControlServer.getMessageStatus(messageId);
睡眠(时间单位为微秒,托米利斯(100));
}
LOG.info(“消息:+messageId+“成功”);
返回true;
}
}

我想知道是否有更好的方法来实现这一点,因为Thread.sleep是阻塞的和丑陋的。

我不确定这是最好的解决方案,但我想到你可以使用
倒计时闩锁
ScheduledExecutorService

    public void poll(final List<Long> messageIdList) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(messageIdList.size());
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(POOL_SIZE);
        try {
            for (Long messageId : messageIdList) {
                MessageStatusCallable callable = new MessageStatusCallable(messageId, latch);
                executorService.scheduleWithFixedDelay(
                        () -> {
                            String messageStatus = downstreamService.getMessageStatus(messageId);
                            if (STATUS_VALUE_SUCCEEDED.equals(messageStatus)) {
                                latch.countDown();
                                throw new CompletionException("Success - killing the task", null);
                            }
                        }, 
                        0, 100, TimeUnit.MILLISECONDS);
            }

            latch.await();

        } finally {
            executorService.shutdown();
        }
    }
public void poll(最终列表messageIdList)抛出InterruptedException{
CountDownLatch latch=新的CountDownLatch(messageIdList.size());
ScheduledExecutorService executorService=Executors.NewsScheduledThreadPool(池大小);
试一试{
for(长messageId:messageIdList){
MessageStatusCallable callable=新MessageStatusCallable(messageId,闩锁);
executorService.scheduleWithFixedDelay(
() -> {
字符串messageStatus=downstreamService.getMessageStatus(messageId);
如果(状态\值\成功。等于(消息状态)){
倒计时();
抛出新的CompletionException(“成功-终止任务”,null);
}
}, 
0,100,时间单位为毫秒);
}
satch.wait();
}最后{
executorService.shutdown();
}
}

除了答案中的简洁性之外,我可能也不会让这个函数作为lambda运行。

您不需要投票。只需调用
Future.get()
在所有的
期货上,以任何顺序。当你得到它们时,你就完成了。@user207421你的意思是我不需要做while循环来轮询下游服务吗?不,我的意思是:你不需要轮询,更不用说while循环了。你所做的就是等待它们全部结束,所以就这样做。@user207421对不起,我没有得到你的point。如果我不轮询,我怎么知道何时停止?一条消息可能需要1秒才能成功,但也可能需要半个小时。如果你的观点意味着不轮询,而只是等待一个固定的时间。谢谢Marc,这是一个比我的好得多的解决方案。我想知道是否有更优雅的方法来完成单个任务?因为我看到你使用CompletionException to关闭一个轮询Taski假设您可以有一个消息ID和预定期货的地图,然后在预定的将来调用取消,或者如果您将任务撤回到一个类中,您可以将回调传递给任务,并且回调可以减少闩锁并取消任务。ut回调调用代码以在检索完所有消息后继续处理。您必须提升执行器的作用域,或者从回调中将其关闭。