Java多线程Future与CompletableFuture-异步获取接口返回结果

简介: 当调用一些耗时接口时,如果我们一直在原地等待方法返回,整体程序的运行效率会大大降低。可以把调用的过程放到子线程去执行,再通过 Future 去控制子线程的调用过程,最后获取到调用结果,来提高整个程序的运行效率。

背景:

当调用一些耗时接口时,如果我们一直在原地等待方法返回,整体程序的运行效率会大大降低。可以把调用的过程放到子线程去执行,再通过 Future 去控制子线程的调用过程,最后获取到计算结果。提高整个程序的运行效率。

创建线程池:

@ConfigurationpublicclassExecutorConfig {
privatefinalstaticintTHREAD_COUNT=Runtime.getRuntime().availableProcessors() *2;
@Bean(name="batchCallThreadPool")
publicThreadPoolExecutorbatchPredictThreadPool() {
returnnewThreadPoolExecutor(THREAD_COUNT, 200, 0L, TimeUnit.MILLISECONDS, newLinkedBlockingQueue<Runnable>(2048),
newThreadFactoryBuilder().setNameFormat("batch-call-pool-%d").build());
    }
}

利用Future获取线程执行结果

importjava.util.List;
importjava.util.Map;
importjava.util.concurrent.ExecutionException;
importjava.util.concurrent.Future;
importjava.util.concurrent.ThreadPoolExecutor;
importjava.util.concurrent.TimeUnit;
importjava.util.concurrent.TimeoutException;
importcom.google.common.collect.Maps;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
publicclassFutureTestService {
@AutowiredprivateCallServicecallService;
@Autowired@Qualifier("batchPredictThreadPool")
privateThreadPoolExecutorbatchPredictThreadPool;
publicvoidfun(List<Long>idList) {
Map<Long, Future<Integer>>futureMap=Maps.newHashMapWithExpectedSize(idList.size());
// 让所有调用的子线程启动,参与竞争for (Longid : idList) {
Future<Integer>future=batchPredictThreadPool.submit(() ->callService.call(id));
futureMap.put(id, future);
        }
for (Longid : futureMap.keySet()) {
try {
// 阻塞获取执行结果,如果 3s 未获取到会抛出超时异常Integerresult=futureMap.get(id).get(3000, TimeUnit.MILLISECONDS);
            } catch (TimeoutExceptione) {
// 处理超时            } catch (ExecutionExceptione) {
// 处理执行时异常            } catch (InterruptedExceptione) {
// 处理 中断            }
        }
    }
}

利用CompletableFuture获取线程执行结果

importjava.util.HashMap;
importjava.util.LinkedList;
importjava.util.List;
importjava.util.Map;
importjava.util.concurrent.CompletableFuture;
importjava.util.concurrent.ExecutionException;
importjava.util.concurrent.ThreadPoolExecutor;
importjava.util.concurrent.TimeUnit;
importjava.util.concurrent.TimeoutException;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
publicclassFutureTestService {
@AutowiredprivateCallServicecallService;
@Autowired@Qualifier("batchPredictThreadPool")
privateThreadPoolExecutorbatchPredictThreadPool;
publicvoidfun(List<Long>idList) throwsExecutionException, InterruptedException, TimeoutException {
List<CompletableFuture<Integer>>completableFutureList=newLinkedList<>();
Map<Long, Integer>resultMap=newHashMap<>(idList.size());
// 让所有调用的子线程启动,参与竞争for (Longid : idList) {
CompletableFuture<Integer>future=CompletableFuture.supplyAsync(() -> {
Integerresult=callService.call(id);
resultMap.put(id, result);
returnnull;
            }, batchPredictThreadPool);
completableFutureList.add(future);
        }
// 在此处聚合CompletableFuture<Void>allCompletableFuture=CompletableFuture.allOf(completableFutureList.toArray(
newCompletableFuture[completableFutureList.size()]));
/*** 如果在 3 秒钟之内这些任务都可以顺利返回,则这个 get 方法就可以及时正常返回,并且往下执行。* 如果有某一个任务没能来得及在 3 秒钟之内返回,那么这个带超时参数的 get 方法便会抛出 TimeoutException 异常* 会尝试等待所有的任务完成,但是最多只会等 3 秒钟,在此之间,如及时完成则及时返回。*/allCompletableFuture.get(3, TimeUnit.SECONDS);
    }
}


目录
相关文章
|
12天前
|
Java Lambda 表达式:以 Foo 接口为例深入解析
本文深入解析了 Java 8 中 Lambda 表达式的用法及其背后的函数式接口原理,以 `Foo` 接口为例,展示了如何通过简洁的 Lambda 表达式替代传统匿名类实现。文章从 Lambda 基本语法、函数式接口定义到实际应用层层递进,并探讨默认方法与静态方法的扩展性,最后总结常见误区与关键点,助你高效优化代码!
36 0
|
12天前
|
java中一个接口A,以及一个实现它的类B,一个A类型的引用对象作为一个方法的参数,这个参数的类型可以是B的类型吗?
本文探讨了面向对象编程中接口与实现类的关系,以及里氏替换原则(LSP)的应用。通过示例代码展示了如何利用多态性将实现类的对象传递给接口类型的参数,满足LSP的要求。LSP确保子类能无缝替换父类或接口,不改变程序行为。接口定义了行为规范,实现类遵循此规范,从而保证了多态性和代码的可维护性。总结来说,接口与实现类的关系天然符合LSP,体现了多态性的核心思想。
23 0
|
13天前
|
【源码】【Java并发】从InheritableThreadLocal和TTL源码的角度来看父子线程传递
本文涉及InheritableThreadLocal和TTL,从源码的角度,分别分析它们是怎么实现父子线程传递的。建议先了解ThreadLocal。
50 4
【源码】【Java并发】从InheritableThreadLocal和TTL源码的角度来看父子线程传递
JAVA接入DeepSeek大模型接口开发---阿里云的百炼模型
随着大模型的越来越盛行,现在很多企业开始接入大模型的接口,今天我从java开发角度来写一个demo的示例,用于接入DeepSeek大模型,国内的大模型有很多的接入渠道,今天主要介绍下阿里云的百炼模型,因为这个模型是免费的,只要注册一个账户,就会免费送百万的token进行学习,今天就从一个简单的可以执行的示例开始进行介绍,希望可以分享给各位正在学习的同学们。
221 3
JAVA接入DeepSeek大模型接口开发---阿里云的百炼模型
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
86 23
|
2月前
|
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
66 17
|
2月前
|
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
67 26
【JavaEE】多线程编程引入——认识Thread类
Thread类,Thread中的run方法,在编程中怎么调度多线程
|
4月前
|
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
360 2

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等