Java中使用同步回调和异步回调的示例详解

 更新时间:2023年04月18日 10:01:52   作者:ZWZhangYu  
这篇文章主要介绍了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执行代码和后面的回调代码是按照顺序执行的。

小结

【1】回调函数应该在执行另一个动作时或与该动作并行执行。
【2】回调函数可以是同步的,这意味着它必须在其他操作之后立即执行,没有任何延迟。
【3】回调函数可以是异步的,这意味着它可以在后台执行,并且可能需要一些时间才能执行。
【4】异步回调需要注意,是在等待当前执行代码完毕后在执行异步回调还是允许直接启动异步线程,允许业务代码和回调业务没有执行顺序要求。
【5】对于回调的代码场景应用可以结合观察者设计模式深入了解。

完整代码

https://github.com/zwzhangyu/ZyCodeHub.git

到此这篇关于Java中使用同步回调和异步回调的示例详解的文章就介绍到这了,更多相关java同步回调和异步回调内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot应用能直接运行java -jar的原因分析

    SpringBoot应用能直接运行java -jar的原因分析

    这篇文章主要介绍了SpringBoot应用为什么能直接运行java -jar,首先明确一点,普通jar包是不能直接运行的,比如工具类jar,要能运行,至少得要一个main函数作为入口吧?本文给大家介绍了详细的原因分析,需要的朋友可以参考下
    2024-03-03
  • Java欧拉函数的计算代码详解

    Java欧拉函数的计算代码详解

    这篇文章主要介绍了Java实现欧拉函数的计算,从欧拉函数引伸出来在环论方面的事实和拉格朗日定理构成了欧拉定理的证明,本文通过实例代码给大家介绍的很详细,需要的朋友可以参考下
    2021-05-05
  • SpringBoot的@ControllerAdvice处理全局异常详解

    SpringBoot的@ControllerAdvice处理全局异常详解

    这篇文章主要介绍了SpringBoot的@ControllerAdvice处理全局异常详解,但有时却往往会产生一些bug,这时候就破坏了返回数据的一致性,导致调用者无法解析,所以我们常常会定义一个全局的异常拦截器,需要的朋友可以参考下
    2024-01-01
  • SpringBoot注册web组件的实现方式

    SpringBoot注册web组件的实现方式

    Servlet是Java Web应用程序的基础,它提供了处理客户端请求的机制,Servlet三大组件是指Servlet、Filter和Listener,它们是Java Web应用程序的核心组件,本文将给大家介绍一下SpringBoot注册web组件的实现方式,需要的朋友可以参考下
    2023-10-10
  • 解决Maven依赖冲突的方法

    解决Maven依赖冲突的方法

    本文主要介绍了解决Maven依赖冲突的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • ArrayList及HashMap的扩容规则讲解

    ArrayList及HashMap的扩容规则讲解

    今天小编就为大家分享一篇关于ArrayList及HashMap的扩容规则讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • 超个性修改SpringBoot项目的启动banner的方法

    超个性修改SpringBoot项目的启动banner的方法

    这篇文章主要介绍了超个性修改SpringBoot项目的启动banner的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Mybatis MapperScannerConfigurer自动扫描Mapper接口生成代理注入到Spring的方法

    Mybatis MapperScannerConfigurer自动扫描Mapper接口生成代理注入到Spring的方法

    这篇文章主要给大家介绍了关于Mybatis MapperScannerConfigurer自动扫描将Mapper接口生成代理注入到Spring的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2019-03-03
  • Java求一个分数数列的前20项之和的实现代码

    Java求一个分数数列的前20项之和的实现代码

    这篇文章主要介绍了Java求一个分数数列的前20项之和的实现代码,需要的朋友可以参考下
    2017-02-02
  • Java内存溢出实现原因及解决方案

    Java内存溢出实现原因及解决方案

    这篇文章主要介绍了Java内存溢出实现原因及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03

最新评论