写点什么

教你如何判断 Java 代码中异步操作是否完成

  • 2024-03-01
    福建
  • 本文字数:4007 字

    阅读完需:约 13 分钟

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


1. 使用 Future 和 Callable


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


javaCopy codeimport java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class AsyncDemo {    public static void main(String[] args) throws Exception {        ExecutorService executorService = Executors.newSingleThreadExecutor();        // 定义异步任务        Callable<String> asyncTask = () -> {            Thread.sleep(2000); // 模拟耗时操作            return "Async task completed";        };        // 提交异步任务        Future<String> future = executorService.submit(asyncTask);        // 判断任务是否完成        while (!future.isDone()) {            System.out.println("Task not done yet...");            Thread.sleep(500);        }        // 获取结果        String result = future.get();        System.out.println(result);        // 关闭线程池        executorService.shutdown();    }}
复制代码


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


2. 使用 CompletableFuture


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


javaCopy codeimport java.util.concurrent.CompletableFuture;import java.util.concurrent.TimeUnit;public class AsyncDemo {    public static void main(String[] args) throws Exception {        // 定义异步任务        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {            try {                TimeUnit.SECONDS.sleep(2); // 模拟耗时操作            } catch (InterruptedException e) {                e.printStackTrace();            }            return "Async task completed";        });        // 判断任务是否完成        while (!future.isDone()) {            System.out.println("Task not done yet...");            TimeUnit.MILLISECONDS.sleep(500);        }        // 获取结果        String result = future.get();        System.out.println(result);    }}
复制代码


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

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


javaCopy codeimport java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;import java.util.ArrayList;import java.util.List;import java.util.concurrent.*;public class AsyncHttpExample {    public static void main(String[] args) throws Exception {        List<Future<String>> futures = new ArrayList<>();                ExecutorService executor = Executors.newFixedThreadPool(5);                List<String> urls = List.of(                "https://www.example.com/api1",                "https://www.example.com/api2",                "https://www.example.com/api3"        );                for (String url : urls) {            Callable<String> task = () -> {                return performRequest(url);            };                        Future<String> future = executor.submit(task);            futures.add(future);        }                executor.shutdown();                for (Future<String> future : futures) {            try {                String result = future.get();                System.out.println("Received response: " + result);            } catch (InterruptedException | ExecutionException e) {                e.printStackTrace();            }        }    }        private static String performRequest(String url) throws IOException {        HttpURLConnection connection = null;        BufferedReader reader = null;        StringBuilder response = new StringBuilder();                try {            URL requestUrl = new URL(url);            connection = (HttpURLConnection) requestUrl.openConnection();            connection.setRequestMethod("GET");                        reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));            String line;                        while ((line = reader.readLine()) != null) {                response.append(line);            }        } finally {            if (connection != null) {                connection.disconnect();            }                        if (reader != null) {                reader.close();            }        }                return response.toString();    }}
复制代码


在这个示例中,我们创建了一个固定大小的线程池,并为每个 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 接口:


javaCopy codeimport java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class CallableExample {    public static void main(String[] args) throws Exception {        Callable<Integer> task = () -> {            int sum = 0;            for (int i = 1; i <= 100; i++) {                sum += i;            }            return sum;        };                ExecutorService executor = Executors.newSingleThreadExecutor();        Future<Integer> future = executor.submit(task);                // 可以在此处执行其他任务                Integer result = future.get(); // 获取任务的结果,会阻塞直到任务完成        System.out.println("Sum: " + result);                executor.shutdown();    }}
复制代码


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


总结


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


文章转载自:华为云开发者联盟

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

体验地址:http://www.jnpfsoft.com/?from=001

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
教你如何判断Java代码中异步操作是否完成_Java_快乐非自愿限量之名_InfoQ写作社区