Java 并发轮询下游依赖项,并等待所有依赖项都成功
我试图编写一个简单的函数,它可以长时间轮询多条消息到下游依赖项,而不会耗尽它,并且只在所有消息成功时才存在 我想出了一种方法,将每个消息轮询包装成一个callable,并使用ExecutorService提交一个callable列表Java 并发轮询下游依赖项,并等待所有依赖项都成功,java,concurrency,Java,Concurrency,我试图编写一个简单的函数,它可以长时间轮询多条消息到下游依赖项,而不会耗尽它,并且只在所有消息成功时才存在 我想出了一种方法,将每个消息轮询包装成一个callable,并使用ExecutorService提交一个callable列表 public void poll(final List<Long> messageIdList) { ExecutorService executorService = Executors.newFixedThreadPool(
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回调调用代码以在检索完所有消息后继续处理。您必须提升执行器的作用域,或者从回调中将其关闭。