CompletableFuture执行多个异步任务,将结果合并返回

该代码示例展示了如何在Java中使用CompletableFuture类来异步执行三个任务。每个任务通过supplyAsync启动并在不同的线程中运行,然后通过get()方法获取结果。尽管最初没有选择线程安全的ConcurrentHashMap,但考虑到不存在并发插入,使用了HashMap。最后,将任务的结果存储在一个Map中并返回。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public Map<String, String> test() throws InterruptedException, ExecutionException {
	// 不存在并发插入情况,不需要使用ConcurrentHashMap
//		Map<String, String> data = new ConcurrentHashMap<>(3);
	Map<String, String> data = new HashMap<>(3);
	//第一个任务。返回参数类型可自定义
	CompletableFuture<String> task01 = CompletableFuture.supplyAsync(() -> {
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "task01";
	});
	//第二个任务。返回参数类型可自定义
	CompletableFuture<String> task02 = CompletableFuture.supplyAsync(() -> {
		try {
			TimeUnit.SECONDS.sleep(5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "task02";
	});
	// 第三个任务。返回参数类型可自定义
	CompletableFuture<String> task03 = CompletableFuture.supplyAsync(() -> {
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "task03";
	});
	// get()方法会阻塞,最终得到处理时间,取决于多线程的最大响应时间的接口
	String task01Result = task01.get() ;
	String task02Result = task02.get() ;
	String task03Result = task03.get() ;
	data.put("task01", task01Result );
	data.put("task02", task02Result );
	data.put("task03", task03Result );
	return data;
}

<think>我们被要求使用JavaCompletableFuture来并发执行多个任务并汇总结果。步骤:1.创建多个任务(例如,Callable或Runnable,但CompletableFuture更常用Supplier或Runnable)。2.使用CompletableFuture.supplyAsync(有返回值)或runAsync(无返回值)来异步执行任务。3.组合这些CompletableFuture,以便等待所有任务完成并收集结果。4.处理可能出现的异常。我们可以使用以下方法之一: -allOf:等待所有的CompletableFuture完成,然后收集结果。注意:allOf不会返回结果集合,需要自己收集。 -使用thenCombine或thenCompose等组合,但如果是多个任务,allOf更合适。示例:假设我们有一组任务,每个任务返回一个字符串,我们想要收集所有字符串结果。注意:使用CompletableFuture时,我们可以指定一个Executor(线程池),如果不指定,则使用默认的ForkJoinPool。另外,在收集结果时,由于allOf返回CompletableFuture<Void>,我们需要在任务创建时保存每个future的引用,以便后续获取结果。代码结构:1.创建任务列表:List<CompletableFuture<String>> futures= ...2.使用CompletableFuture.allOf(futures.toArray(newCompletableFuture[0])).join();等待所有任务完成。3.然后遍历futures列表,使用future.join()获取每个任务结果(此时不会阻塞,因为已经全部完成)。但是,注意:如果某个任务出现异常,join()会抛出CompletionException。我们可以使用exceptionally等方法来处理异常。另一种方式是使用Stream:例如: List<CompletableFuture<String>> futures= ...; CompletableFuture<Void> all=CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); CompletableFuture<List<String>> result=all.thenApply(v ->futures.stream().map(CompletableFuture::join).collect(Collectors.toList()));然后我们可以通过result.get()来获取最终的结果列表。但是,这样处理异常的话,如果某个任务异常,那么join()会抛出异常,导致整个结果获取失败。我们可以使用异常处理机制,例如在创建每个future时处理异常(返回一个默认值),或者在收集结果时跳过异常。根据需求,我们可以选择: -如果希望所有任务都成功,则让异常传播。 -如果希望即使有任务失败也能收集部分结果,则需要在每个future上使用exceptionally或handle方法。示例:每个任务返回字符串,我们允许任务失败时返回一个默认值(例如"error")。下面我们写一个完整的示例代码:</think>### Java CompletableFuture 并发执行任务并汇总结果Java 中使用 `CompletableFuture` 并发执行多个任务并汇总结果的实现步骤如下: #### 1. **基础实现** ```java import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.stream.Collectors; public class CompletableFutureDemo { // 模拟耗时任务(实际替换为业务逻辑) static String task(int id) { try { Thread.sleep(1000); // 模拟任务耗时 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return "Result-" + id; } public static void main(String[] args) { // 1. 创建任务列表(示例:10个任务) List<CompletableFuture<String>> futures = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).stream() .map(id -> CompletableFuture.supplyAsync(() -> task(id))) .collect(Collectors.toList()); // 2. 合并所有任务结果 CompletableFuture<Void> allFutures = CompletableFuture.allOf( futures.toArray(new CompletableFuture[0]) ); // 3. 提取结果并汇总 CompletableFuture<List<String>> results = allFutures.thenApply(v -> futures.stream() .map(CompletableFuture::join) // 获取每个任务结果 .collect(Collectors.toList()) ); // 4. 阻塞获取最终结果 List<String> finalResults = results.join(); System.out.println("汇总结果: " + finalResults); } } ``` #### 2. **关键优化点** 1. **自定义线程池** 避免使用默认的 `ForkJoinPool`,防止资源耗尽: ```java Executor customPool = Executors.newFixedThreadPool(10); CompletableFuture.supplyAsync(() -> task(id), customPool); // 指定线程池 ``` 2. **异常处理** 使用 `handle()` 或 `exceptionally()` 处理任务异常: ```java .map(id -> CompletableFuture.supplyAsync(() -> task(id)) .handle((res, ex) -> ex != null ? "Error: " + ex.getMessage() : res)) ``` 3. **超时控制** 通过 `orTimeout()` 设置单任务超时(Java 9+): ```java .map(id -> CompletableFuture.supplyAsync(() -> task(id)) .orTimeout(2, TimeUnit.SECONDS)) ``` #### 3. **执行流程** 1. **任务提交** `supplyAsync()` 异步提交任务,立即返回 `CompletableFuture` 对象。 2. **结果合并** `allOf()` 创建组合 Future,当所有子任务完成时触发完成事件。 3. **结果提取** `thenApply()` 在所有任务完成后提取结果列表,通过 `join()` 安全获取值。 4. **阻塞等待** 最终调用 `results.join()` 阻塞主线程直到所有结果就绪。 #### 4. **性能特点** - **并发性**:所有任务并行执行,总耗时 ≈ 最慢任务的耗时 - **非阻塞**:主线程在 `allOf().thenApply()` 链中无等待 - **资源可控**:通过线程池限制并发线程数 > **注意**:`CompletableFuture.join()` 会抛出未检查异常,需在链式调用中处理错误[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值