java异步编程
Java 提供了几种异步编程方式,尤其是在 Java 8 引入的 CompletableFuture
和 Java 11 的 HttpClient
中,能够实现异步操作。
1. CompletableFuture
(Java 8)
CompletableFuture
是 Java 中用于处理异步任务的类,它提供了类似于 C# async/await
的功能,可以链式操作并组合多个异步任务。
示例:使用 CompletableFuture
import java.util.concurrent.CompletableFuture;
public class AsyncExample {
public static void main(String[] args) {
// 异步调用
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello, World!";
});
// 异步完成后执行操作
future.thenAccept(result -> {
System.out.println("Result: " + result);
});
// 继续执行其他任务
System.out.println("Doing other work...");
// 主线程等待异步操作完成
future.join(); // 等待异步任务完成
}
}
在这个示例中,supplyAsync
方法用于启动一个异步任务,thenAccept
用于处理任务完成后的结果。类似于 C# 中的 await
,join()
会阻塞,直到异步任务完成。
2. HttpClient
(Java 11)
Java 11 引入了新的 HttpClient
,支持异步 HTTP 请求,结合 CompletableFuture
实现异步调用。
示例:使用 HttpClient
进行异步 HTTP 请求
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
public class AsyncHttpClientExample {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://jsonplaceholder.typicode.com/posts/1"))
.build();
// 异步发送请求
CompletableFuture<HttpResponse<String>> future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
// 处理响应
future.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join(); // 等待异步任务完成
}
}
这里的 sendAsync
方法是非阻塞的,返回一个 CompletableFuture
,可以在响应准备好时处理。
3. 使用第三方库
如果你想要更接近 C# async/await
语法的体验,可以使用第三方库如 Project Loom 或 ReactiveX (RxJava),它们可以帮助简化异步编程,特别是在并发任务较多的场景下。
1. 基本概念
CompletableFuture
是Future
的增强版,支持非阻塞的异步操作。它允许你通过链式调用处理异步任务的结果。- 支持异步计算、组合多个任务、处理异常等功能,非常适用于并发和异步编程。
2. 创建 CompletableFuture
- 直接创建已完成的
CompletableFuture
:CompletableFuture<String> completedFuture = CompletableFuture.completedFuture("Hello");
- 异步任务:使用
runAsync
或supplyAsync
启动异步任务。CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 任务逻辑 }); CompletableFuture<String> futureWithResult = CompletableFuture.supplyAsync(() -> { return "Result"; });
3. 组合任务
- thenApply:对任务结果进行转换或处理。
future.thenApply(result -> result.toUpperCase());
- thenAccept:处理结果但不返回值。
future.thenAccept(result -> System.out.println(result));
- thenRun:在任务完成后执行某个操作,不关心结果。
future.thenRun(() -> System.out.println("Task completed"));
- thenCombine:将两个异步任务的结果进行组合。
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + result2);
4. 异常处理
- exceptionally:处理异常并返回替代结果。
future.exceptionally(ex -> { System.out.println("Error: " + ex.getMessage()); return "Fallback result"; });
- handle:无论任务成功或失败,都会执行,可以分别处理结果和异常。
future.handle((result, ex) -> { if (ex != null) { System.out.println("Error: " + ex.getMessage()); return "Fallback result"; } else { return result; } });
5. 组合多个 CompletableFuture
- allOf:等待所有
CompletableFuture
完成。CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);
- anyOf:只要有一个
CompletableFuture
完成就继续。CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);
6. 异步回调执行器
- 可以使用自定义线程池来执行异步任务,而不是使用默认的
ForkJoinPool
。CompletableFuture.supplyAsync(() -> "Result", executor);
7. 典型用例
- 并行任务执行:当需要同时执行多个异步任务时,可以通过
thenCombine
或allOf
进行组合,来提高并行处理效率。 - 异步操作链:使用
thenApply
、thenCompose
构建任务链,使代码更加简洁清晰。 - 处理异步任务中的异常:利用
exceptionally
或handle
处理异步任务中可能发生的异常,保证系统的鲁棒性。
8. 性能注意事项
- 使用
CompletableFuture
提供的默认线程池适合大多数场景,但在高负载或需要精细控制的场景下,最好创建自定义线程池。 - 对于IO密集型任务,可以考虑调整线程池的大小,以便合理利用资源。
总结来说,CompletableFuture
是处理异步和并发任务的强大工具,它可以通过链式操作简化任务的组合与异常处理