本篇内容主要讲解“Java中怎么使用同步回调和异步回调”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java中怎么使用同步回调和异步回调”吧!
(一)同步回调
同步回调函数将始终在执行某些操作后立即执行。这意味着它将与执行该操作的函数同步。
在观察者设计模式中可以找到回调函数的示例。在需要单击按钮以启动某些操作的应用界面中,我们可以将回调函数作为该按钮单击的监听器传递。监听器函数等待按钮被单击,然后执行监听器回调。
(1)匿名内部类回调
每当我们将带有方法实现的接口传递给 Java 中的另一个方法时,我们都在使用回调函数的概念。在下面的代码中,我们将通过 Consumer 功能接口和一个匿名内部类(没有名称的实现)来实现 accept() 方法。
实现 accept() 方法后,我们将执行 performAction 方法中的操作;然后我们将从 Consumer 接口执行 accept() 方法:
import java.util.function.Consumer; /** * 同步场景下匿名内部类的方式实现回调 * * @author zhangyu * @date 2023/4/16 */ public class AnonymousClassCallback { public static void main(String[] args) { performAction(new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }); } public static void performAction(Consumer<String> consumer) { System.out.println("执行特定的业务逻辑"); consumer.accept("回调代码被执行"); } }
在这段代码中,我们将 Consumer 接口传递给 performAction() 方法,然后在操作完成后调用 accept() 方法。
(2)Lambda 回调
观察上面的代码可能还会注意到使用匿名内部类非常冗长。改用 lambda 会好得多。
/** * 同步场景下匿名内部类的方式实现回调(Lambda写法) * * @author zhangyu * @date 2023/4/16 */ public class LambdaCallback { public static void main(String[] args) { performAction(() -> System.out.println("回调代码被执行")); } public static void performAction(Runnable runnable) { System.out.println("执行特定的业务逻辑"); runnable.run(); } }
输出再次表明正在执行操作并执行回调。
(二)异步回调
通常,我们希望使用异步回调方法,这意味着将在操作之后调用但与其他线程异步调用的方法。当不需要在其他线程之后立即调用回调方法时,这可能有助于提高性能。
(1)简单的线程回调
在下面的代码中,首先我们将从 Runnable 功能接口实现 run() 方法。然后,我们将创建一个 Thread 并使用我们刚刚在 Thread 中实现的 run() 方法。最后,我们启动线程异步执行:
/ /** * 异步回调实例 * * @author zhangyu * @date 2023/4/16 */ public class AsynchronousCallback { public static void main(String[] args) { Runnable runnable = () -> System.out.println("回调代码被执行"); AsynchronousCallback asynchronousCallback = new AsynchronousCallback(); asynchronousCallback.performAsynchronousAction(runnable); } public void performAsynchronousAction(Runnable runnable) { new Thread(() -> { System.out.println("执行异步操作代码"); runnable.run(); }).start(); } }
在上面的代码中,首先我们为 Runnable 中的 run() 方法创建了一个实现。然后,我们调用了 performAsynchronousAction() 方法,传递带有 run() 方法实现的可运行功能接口。 在 performAsynchronousAction() 中,我们传递 runnable 接口并使用 lambda 在 Thread 中实现另一个 Runnable 接口。
(2)异步并行回调
除了在异步操作中调用回调函数之外,我们还可以在调用另一个函数的同时调用回调函数。这意味着我们可以启动两个线程并并行调用这些方法。 代码将与前面的示例类似,但请注意,我们将启动一个新线程并在这个新线程中调用回调函数,而不是直接调用回调函数:
/** * 异步并行回调 * * @author zhangyu * @date 2023/4/16 */ public class AsynchronousParallelCallback { public void performAsynchronousAction(Runnable runnable) { new Thread(() -> { System.out.println("执行异步操作代码"); // 创建一个新的线程执行回调 new Thread(runnable).start(); }).start(); } public static void main(String[] args) { Runnable runnable = () -> System.out.println("回调代码被执行"); AsynchronousParallelCallback callback = new AsynchronousParallelCallback(); callback.performAsynchronousAction(runnable); } }
当我们不需要在 performAsynchronousAction() 方法的操作之后立即执行回调函数时,异步并行回调很有用。 一个真实的例子是当我们在线购买产品时,我们不需要等到确认付款、检查库存以及所有那些繁重的流程。在这种情况下,我们可以在后台执行回调调用的同时做其他事情。CompletableFuture 回调
(3)CompletableFuture 回调
另一种使用异步回调函数的方法是使用 CompletableFuture API。这个强大的 API 在 Java 8 中引入,有助于执行和组合异步方法调用。它完成了我们在前面的示例中所做的一切,例如创建一个新线程然后启动和管理它。 在下面的代码示例中,我们将创建一个新的 CompletableFuture,然后我们将调用传递字符串的 supplyAsync 方法。 接下来,我们将创建另一个 CompletableFuture,然后应用一个回调函数来执行我们配置的第一个函数:
import java.util.concurrent.CompletableFuture; /** * CompletableFuture callback * * @author zhangyu * @date 2023/4/16 */ public class CompletableFutureCallback { public static void main(String[] args) throws Exception { CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> { System.out.println("执行业务代码"); try { Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("执行业务代码结束"); return "ok"; }); CompletableFuture<String> execution = completableFuture .thenApply(s -> s + "回调被执行"); System.out.println("main线程执行代码"); System.out.println(execution.get()); } }
注意在上面的代码示例中,CompletableFuture开启了一个新的线程,因此其对应的代码是在新的线程中执行的,因为代码中Thread.sleep(2000);所以main线程执行代码内容先打印了出来。再者可以看到在CompletableFuture执行代码和后面的回调代码是按照顺序执行的。