经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
教你如何判断Java代码中异步操作是否完成
来源:cnblogs  作者:华为云开发者联盟  时间:2024/2/26 15:07:08  对本文有异议
本文分享自华为云社区《java代码实现异步返回结果如何判断异步执行完成》,作者: 皮牙子抓饭。

在许多应用程序中,我们经常使用异步操作来提高性能和响应度。在Java中,我们可以使用多线程或者异步任务来执行耗时操作,并且在后台处理过程完成后获取结果。但是,在使用异步操作时,我们通常需要知道异步任务何时完成,以便进行下一步的操作。 本篇文章将介绍几种常见的方法来判断Java代码中异步操作是否完成。

1. 使用Future和Callable

Java中的Future接口定义了一种方式来表示异步操作的未来结果。我们可以使用Callable接口来定义异步任务,它返回一个Future对象,我们可以利用Future对象的方法来检查任务是否完成。 下面是一个例子:

  1. javaCopy code
  2. import java.util.concurrent.Callable;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Future;
  6. public class AsyncDemo {
  7. public static void main(String[] args) throws Exception {
  8. ExecutorService executorService = Executors.newSingleThreadExecutor();
  9. // 定义异步任务
  10. Callable<String> asyncTask = () -> {
  11. Thread.sleep(2000); // 模拟耗时操作
  12. return "Async task completed";
  13. };
  14. // 提交异步任务
  15. Future<String> future = executorService.submit(asyncTask);
  16. // 判断任务是否完成
  17. while (!future.isDone()) {
  18. System.out.println("Task not done yet...");
  19. Thread.sleep(500);
  20. }
  21. // 获取结果
  22. String result = future.get();
  23. System.out.println(result);
  24. // 关闭线程池
  25. executorService.shutdown();
  26. }
  27. }

在上面的代码中,我们创建了一个单线程的ExecutorService来执行异步任务。我们使用submit方法提交异步任务,并得到一个Future对象。然后,我们可以使用isDone()方法来判断任务是否完成,如果任务没有完成,则等待片刻后再次检查。一旦任务完成,我们可以使用get()方法获取任务的结果。

2. 使用CompletableFuture

自Java 8起,Java提供了CompletableFuture类来更加方便地处理异步操作。CompletableFuture是Future的一个实现,同时也支持对未来结果的处理和组合。 下面是一个例子:

  1. javaCopy code
  2. import java.util.concurrent.CompletableFuture;
  3. import java.util.concurrent.TimeUnit;
  4. public class AsyncDemo {
  5. public static void main(String[] args) throws Exception {
  6. // 定义异步任务
  7. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
  8. try {
  9. TimeUnit.SECONDS.sleep(2); // 模拟耗时操作
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. return "Async task completed";
  14. });
  15. // 判断任务是否完成
  16. while (!future.isDone()) {
  17. System.out.println("Task not done yet...");
  18. TimeUnit.MILLISECONDS.sleep(500);
  19. }
  20. // 获取结果
  21. String result = future.get();
  22. System.out.println(result);
  23. }
  24. }

在上述代码中,我们使用supplyAsync方法创建了一个CompletableFuture对象,并定义了异步任务。然后,我们可以使用isDone()方法来判断任务是否完成。通过调用get()方法可以获取最终的结果。

当涉及到实际应用场景时,异步操作的一个常见用例是在Web应用中执行并行的HTTP请求以提高性能。以下是一个示例代码,展示了如何使用异步操作来执行多个HTTP请求,并在所有请求完成后进行处理。

  1. javaCopy code
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.net.HttpURLConnection;
  6. import java.net.URL;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9. import java.util.concurrent.*;
  10. public class AsyncHttpExample {
  11. public static void main(String[] args) throws Exception {
  12. List<Future<String>> futures = new ArrayList<>();
  13. ExecutorService executor = Executors.newFixedThreadPool(5);
  14. List<String> urls = List.of(
  15. "https://www.example.com/api1",
  16. "https://www.example.com/api2",
  17. "https://www.example.com/api3"
  18. );
  19. for (String url : urls) {
  20. Callable<String> task = () -> {
  21. return performRequest(url);
  22. };
  23. Future<String> future = executor.submit(task);
  24. futures.add(future);
  25. }
  26. executor.shutdown();
  27. for (Future<String> future : futures) {
  28. try {
  29. String result = future.get();
  30. System.out.println("Received response: " + result);
  31. } catch (InterruptedException | ExecutionException e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. }
  36. private static String performRequest(String url) throws IOException {
  37. HttpURLConnection connection = null;
  38. BufferedReader reader = null;
  39. StringBuilder response = new StringBuilder();
  40. try {
  41. URL requestUrl = new URL(url);
  42. connection = (HttpURLConnection) requestUrl.openConnection();
  43. connection.setRequestMethod("GET");
  44. reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
  45. String line;
  46. while ((line = reader.readLine()) != null) {
  47. response.append(line);
  48. }
  49. } finally {
  50. if (connection != null) {
  51. connection.disconnect();
  52. }
  53. if (reader != null) {
  54. reader.close();
  55. }
  56. }
  57. return response.toString();
  58. }
  59. }

在这个示例中,我们创建了一个固定大小的线程池,并为每个URL创建了一个异步任务。每个任务在自己的线程中执行HTTP请求,并返回响应结果。我们使用Future来跟踪每个任务的执行状态和结果。一旦所有任务都被提交,我们调用shutdown()方法关闭线程池,然后通过迭代每个Future对象,使用get()方法获取任务的结果。最后,我们可以根据需要对结果进行进一步处理,这里只是简单地打印出每个请求的响应。

java.util.concurrent.Callable 是 Java 并发编程中的一个接口,它表示一个可调用的任务,可以在计算中返回一个值。与 Runnable 接口不同,Callable 接口的 call() 方法可以返回一个结果,并且可以在执行过程中抛出受检异常。 Callable 接口定义了以下方法:

  • V call() throws Exception:执行任务并返回结果。可以抛出受检异常。
  • boolean equals(Object obj):比较该 Callable 与指定对象是否相等。
  • default <U> Callable<U> compose(Function<? super V, ? extends U> var1):将该 Callable 的结果应用于给定函数,并返回 Callable。
  • default <V2> Callable<V2> andThen(Function<? super V, ? extends V2> var1):将给定函数应用于该 Callable 的结果,并返回新的 Callable。
  • default Predicate<V> isEqual(Object var1):返回谓词,用于判断对象是否与这个 Callable 的结果相等。
  • default Supplier<V> toSupplier():返回将该 Callable 的结果作为值的供应商。 在实际应用中,Callable 接口常常与 ExecutorService 结合使用,通过将 Callable 对象提交给线程池来执行。线程池会返回一个 Future 对象,用于跟踪任务的执行状态和获取结果。 以下是一个示例代码,展示了如何使用 Callable 接口:
  1. javaCopy code
  2. import java.util.concurrent.Callable;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Future;
  6. public class CallableExample {
  7. public static void main(String[] args) throws Exception {
  8. Callable<Integer> task = () -> {
  9. int sum = 0;
  10. for (int i = 1; i <= 100; i++) {
  11. sum += i;
  12. }
  13. return sum;
  14. };
  15. ExecutorService executor = Executors.newSingleThreadExecutor();
  16. Future<Integer> future = executor.submit(task);
  17. // 可以在此处执行其他任务
  18. Integer result = future.get(); // 获取任务的结果,会阻塞直到任务完成
  19. System.out.println("Sum: " + result);
  20. executor.shutdown();
  21. }
  22. }

在上述示例中,我们创建了一个实现了 Callable 接口的任务,并将其提交给一个单线程的线程池来执行。我们通过 Future 对象来获取 Callable 任务的执行结果,其中 get() 方法会阻塞当前线程,直到任务完成并返回结果。

总结

通过使用Future和CompletableFuture,我们可以方便地判断Java代码中异步操作的执行是否完成。这样,我们就可以在异步操作完成后获取结果,并且继续进行后续的操作。这种方式提高了代码的响应性和性能,使我们能够更好地处理并发和异步任务。

 

点击关注,第一时间了解华为云新鲜技术~

 

原文链接:https://www.cnblogs.com/huaweiyun/p/18033769

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号