在现代软件开发中,处理并发任务是一项常见的挑战。而Java中的CompletableFuture作为一种强大的并发编程工具,为我们提供了丰富的功能和灵活的操作方式。本文将深入探讨CompletableFuture的高级用法,结合实际案例,带你领略并发编程的新境界。
CompletableFuture是Java 8中新增的一种异步编程工具,它基于Future和Promise的概念,提供了更加便利和强大的并发编程能力。CompletableFuture可以用于执行异步任务、组合多个任务的结果、处理异常情况等,是处理并发任务的神器之一。
CompletableFuture的基本用法
在开始探索CompletableFuture的高级用法之前,我们先来回顾一下CompletableFuture的基本用法,包括创建、完成、结合、处理异常等。
// 创建CompletableFuture对象
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "Hello";
});
// 链式调用:组合多个CompletableFuture
CompletableFuture<String> combinedFuture = future.thenApplyAsync(result -> {
return result + " World";
});
// 异常处理
CompletableFuture<String> exceptionFuture = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("Oops! Something went wrong.");
}).exceptionally(ex -> {
return "Error: " + ex.getMessage();
});
异步任务的异常处理
异步任务的异常处理是使用CompletableFuture时需要重点考虑的一个方面。当异步任务中出现异常时,我们需要能够及时捕获并处理异常,以保证程序的稳定性和可靠性。在CompletableFuture中,可以通过exceptionally
方法来处理异步任务的异常情况。
1. supplyAsync任务中的异常处理
在使用CompletableFuture.supplyAsync
创建异步任务时,如果任务执行过程中抛出了异常,可以通过exceptionally
方法进行异常处理。例如:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟一个异常情况
throw new RuntimeException("Oops! Something went wrong.");
}).exceptionally(ex -> {
// 异常处理
System.out.println("Exception caught: " + ex.getMessage());
return "Default value"; // 返回默认值
});
在这个示例中,如果异步任务执行过程中抛出了RuntimeException,那么异常将被捕获,并且exceptionally
方法中的异常处理逻辑将被执行,同时返回了一个默认值作为补救措施。
2. thenApply任务链中的异常处理
在使用thenApply
方法创建任务链时,如果前一个任务执行过程中抛出了异常,后续的任务将不会被执行,并且整个任务链将转入异常处理流程。例如:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟一个异常情况
throw new RuntimeException("Oops! Something went wrong.");
}).thenApply(result -> {
// 此处不会被执行
return result.toUpperCase();
}).thenApply(result -> {
// 此处不会被执行
return result + " World";
}).exceptionally(ex -> {
// 异常处理
System.out.println("Exception caught: " + ex.getMessage());
return "Default value"; // 返回默认值
});
在这个示例中,由于第一个任务抛出了RuntimeException,后续的thenApply
方法不会被执行,而是直接转入了异常处理流程。
3. thenAccept任务链中的异常处理
与thenApply
类似,thenAccept
方法也会在前一个任务执行过程中抛出异常时立即转入异常处理流程,后续的任务也不会被执行。例如:
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
// 模拟一个异常情况
throw new RuntimeException("Oops! Something went wrong.");
}).thenAccept(result -> {
// 此处不会被执行
System.out.println("Result: " + result);
}).thenAccept(result -> {
// 此处不会被执行
System.out.println("Result: " + result);
}).exceptionally(ex -> {
// 异常处理
System.out.println("Exception caught: " + ex.getMessage());
return null;
});
在这个示例中,由于第一个任务抛出了RuntimeException,后续的thenAccept
方法也不会被执行,而是直接转入了异常处理流程。
CompletableFuture的高级用法
组合多个CompletableFuture
CompletableFuture提供了丰富的方法来组合多个CompletableFuture,包括thenCompose、thenCombine、thenAcceptBoth等。以下是一个示例:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
return result1 + " " + result2;
});
异步任务的并行执行
CompletableFuture可以用于执行多个异步任务,并行处理结果。以下是一个示例:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
allOfFuture.thenRun(() -> {
System.out.println("All tasks completed.");
});
超时处理
CompletableFuture还支持设置任务的超时时间,并在超时后执行特定的操作。以下是一个示例:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
});
CompletableFuture<String> timeoutFuture = future.orTimeout(1, TimeUnit.SECONDS);
timeoutFuture.exceptionally(ex -> {
return "Task timed out.";
});
实战案例:使用CompletableFuture处理并发任务
现在,让我们通过一个实际的案例来演示如何使用CompletableFuture处理并发任务。
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "World";
});
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
return result1 + " " + result2;
});
combinedFuture.thenAccept(result -> {
System.out.println("Combined result: " + result);
});
// 主线程等待异步任务完成
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在这个示例中,我们创建了两个CompletableFuture来模拟两个异步任务,分别返回"Hello"和"World"。然后,我们使用thenCombine
方法组合这两个任务的结果,并在任务完成后打印组合的结果。
总结
通过本文的介绍,你已经了解了CompletableFuture的高级用法,包括组合多个CompletableFuture、并行执行任务、超时处理等。CompletableFuture作为Java并发编程的神器之一,为我们提供了强大的异步编程能力,可以大大提高并发任务的处理效率和性能。未来,随着Java并发编程技术的不断发展和完善,我们可以期待CompletableFuture在更多场景下的应用和突破。