在 java 中实现并行执行,核心是利用 completablefuture 提供的异步任务编排能力。具体做法是调用 supplyasync() 或 runasync() 方法将任务提交到线程池,并通过 allof() 等待所有任务完成,或者使用 thencombine() 合并结果。这样做可以让多个耗时操作同时运行,从而缩短整体响应时间。

如何创建并启动异步任务
要启动并行任务,必须使用 CompletableFuture.supplyAsync() 来提交一个返回值的 Callable 任务。该方法会将任务放入默认的 ForkJoinPool 中执行,如果未指定线程池,它将自动从公共池中获取线程。这一步是并行执行的起点,确保任务不会阻塞当前主线程。

import java.util.concurrent.CompletableFuture;
public class ParallelExample {
public static void main(String[] args) throws Exception {
// 启动第一个异步任务
CompletableFuture<string> task1 = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
return "Task 1 Result";
});
// 启动第二个异步任务
CompletableFuture<string> task2 = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
return "Task 2 Result";
});
// 等待两个任务都完成并获取结果
String result1 = task1.get();
String result2 = task2.get();
System.out.println("Result 1: " + result1);
System.out.println("Result 2: " + result2);
}
}</string></string>
上述代码展示了最基础的并行启动方式。两个 supplyAsync 调用几乎同时触发,各自在独立的线程中运行。由于它们互不依赖,可以完全并行执行。最终通过 get() 方法阻塞获取结果,确保程序在输出前已完成所有计算。
如何等待所有任务完成并合并结果
当有多个并行任务需要统一处理时,应使用 CompletableFuture.allOf() 来等待所有 Future 对象完成。这个方法接受可变数量的 CompletableFuture 参数,返回一个新的 CompletableFuture。一旦所有传入的任务完成,该 Future 即被标记为完成,此时可以安全地遍历原任务列表获取各自的结果。

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class AllOfExample {
public static void main(String[] args) throws Exception {
List<completablefuture>> futures = Arrays.asList(
CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(500); } catch (InterruptedException e) {}
return "Data A";
}),
CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(500); } catch (InterruptedException e) {}
return "Data B";
})
);
// 等待所有任务完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
// 收集结果
List<string> results = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
System.out.println("All Results: " + results);
}
}</string></completablefuture>
在这个示例中,allOf 确保了无论哪个任务先完成,主逻辑都会等待所有任务结束。随后通过 stream().map(CompletableFuture::join) 提取结果。这种方式比逐个调用 get() 更优雅,且能更好地处理异常传播(如果某个任务抛出异常,join() 会重新抛出该异常)。
并行执行中如何处理单个任务的异常
在并行执行过程中,如果某个异步任务抛出未捕获的异常,该任务的 CompletableFuture 会被标记为异常状态。此时,直接调用 get() 或 join() 会抛出 ExecutionException。为了不影响其他并行任务的正常执行,可以使用 exceptionally() 方法为每个任务设置异常处理器,提供默认值或日志记录,从而保证整体流程的健壮性。
import java.util.concurrent.CompletableFuture;
public class ExceptionHandlingExample {
public static void main(String[] args) throws Exception {
CompletableFuture<string> failingTask = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("Simulated Error");
}).exceptionally(ex -> {
System.err.println("Error caught: " + ex.getMessage());
return "Default Value";
});
CompletableFuture<string> successTask = CompletableFuture.supplyAsync(() -> {
return "Success";
});
// 即使 failingTask 出错,successTask 仍正常执行
String res1 = failingTask.join();
String res2 = successTask.join();
System.out.println("Res1: " + res1);
System.out.println("Res2: " + res2);
}
}</string></string>
通过 exceptionally,我们将异常转换为一个正常的返回值,避免了程序崩溃。这在并行场景中尤为重要,因为一个任务的失败不应导致整个并行批处理的中断。其他任务如 successTask 会继续独立运行并返回正确结果。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











