在Java中,CompletableFuture是一种强大的异步编程工具,它提供了许多方便的方法来构建高效的异步工作流。本文将介绍CompletableFuture的基本概念,并通过实例演示如何使用CompletableFuture来构建高效的异步工作流。
异步编程和CompletableFuture
在传统的同步编程中,代码按照顺序依次执行,每个任务都需要等待前一个任务完成后才能执行。这种方式在一些场景下会导致效率低下,因为某些任务可能是可以并行执行的。
异步编程则允许我们在执行某个任务时,不必等待其完全执行完成,而是可以继续执行其他任务。这种方式可以提升性能并提高响应速度。
CompletableFuture是Java 8引入的一种用于异步编程的工具类。它提供了丰富的方法和操作符,可以方便地构建异步工作流,实现任务的串联、并行执行、等待多个任务完成等。
CompletableFuture的基本用法
CompletableFuture可以通过CompletableFuture.supplyAsync()
方法创建一个异步任务。该方法接受一个Supplier
函数,用于执行任务并返回结果。
下面是一个简单的例子,演示了如何使用CompletableFuture
创建一个异步任务,并使用thenApply()
方法对结果进行处理:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 执行耗时的任务
return "Hello";
}).thenApply(result -> result + " World");
future.get(); // 获取执行结果,如果任务还没有完成,则会阻塞等待
在上面的例子中,supplyAsync()
方法会在一个新的线程中执行其参数函数,并返回一个CompletableFuture
对象。我们可以通过调用thenApply()
方法来链式地处理结果,该方法会在任务完成后以lambda表达式的形式接收结果并进行处理。
构建异步工作流
CompletableFuture提供了一系列方法来构建异步工作流。通过这些方法,我们可以方便地串联多个任务,实现任务的并行执行、条件执行等。
串联任务
使用thenApply()
方法可以简单地串联多个任务。每个thenApply()
方法都是在上一个任务完成后调用,并且上一个任务的执行结果会作为参数传递给当前任务。
下面是一个示例,展示了如何通过thenApply()
方法串联两个任务:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 执行第一个任务
return "Hello";
}).thenApply(result -> {
// 执行第二个任务,参数result是上一个任务的结果
return result + " World";
});
future.get(); // Hello World
并行执行任务
有时候,我们希望多个任务可以并行执行,以提高效率。CompletableFuture提供了一系列thenCombine()
、allOf()
和anyOf()
等方法来支持并行执行任务。
thenCombine()
方法可以组合两个任务的结果,并在两个任务都完成后触发回调:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 执行任务1
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 执行任务2
return "World";
});
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
// 对结果进行组合处理
return result1 + " " + result2;
});
combinedFuture.get(); // Hello World
allOf()
方法接收一个CompletableFuture
数组,并在所有任务完成后触发回调。下面的例子展示了如何使用allOf()
方法等待并组合多个任务的结果:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 执行任务1
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 执行任务2
return "World";
});
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);
CompletableFuture<List<String>> combinedFuture = allFutures.thenApply(v -> {
return Stream.of(future1, future2)
.map(CompletableFuture::join) // 获取任务结果
.collect(Collectors.toList());
});
combinedFuture.get(); // [Hello, World]
anyOf()
方法接收一个CompletableFuture
数组,并在任一任务完成后触发回调。下面的例子演示了如何使用anyOf()
方法只获取最快完成的任务结果:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 执行任务1
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 执行任务2
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "World";
});
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2);
anyOfFuture.get(); // Hello
条件执行任务
有时候,我们希望根据任务的执行结果来决定下一步的操作。CompletableFuture提供了一些方法来支持条件执行任务,比如thenApplyAsync()
、thenCompose()
、thenAcceptBoth()
等。
thenApplyAsync()
方法可以指定一个Executor
线程池,用于在任务完成后执行回调。这样可以避免回调方法阻塞主线程。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 执行任务1
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 执行任务2
return "World";
});
CompletableFuture<String> conditionalFuture = future1.thenApplyAsync(result1 -> {
if (result1.equals("Hello")) {
return result1.toUpperCase();
} else {
return "Invalid";
}
});
conditionalFuture.get(); // HELLO
thenCompose()
方法可以在一个任务完成后,将其结果作为参数传递给下一个任务。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 执行任务1
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 执行任务2
return " World";
});
CompletableFuture<String> composedFuture = future1.thenCompose(result1 -> {
// 在任务1完成后执行任务2,并将任务1的结果和任务2的结果组合
return CompletableFuture.supplyAsync(() -> result1 + " World");
});
composedFuture.get(); // Hello World
thenAcceptBoth()
方法可以在两个任务都完成后触发回调,将两个任务的结果作为参数传递给回调方法。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 执行任务1
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 执行任务2
return " World";
});
CompletableFuture<Void> acceptBothFuture = future1.thenAcceptBoth(future2, (result1, result2) -> {
// 对任务1和任务2的结果进行处理
System.out.println(result1 + result2); // Hello World
});
acceptBothFuture.get(); // null
总结
CompletableFuture是Java 8引入的一种强大的异步编程工具,它提供了丰富的方法来构建高效的异步工作流。本文介绍了CompletableFuture的基本概念,并通过实例演示了如何使用CompletableFuture来串联任务、并行执行任务、条件执行任务等。
使用CompletableFuture可以提高代码的效率和响应能力,同时提供了更好的编程体验和可读性。在实际开发中,我们可以根据具体需求选择合适的方法和操作符来构建异步工作流,从而更好地利用多核处理器和异步执行任务。
本文来自极简博客,作者:独步天下,转载请注明原文链接:CompletableFuture实战:构建高效异步工作流