如何在Java中使用同步回调和异步回调

news2024/11/16 8:25:42

文章目录

  • (一)同步回调
      • (1)匿名内部类回调
      • (2)Lambda 回调
  • (二)异步回调
      • (1)简单的线程回调
      • (2)异步并行回调
      • (3)CompletableFuture 回调
  • 小结
  • 完整代码

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
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/420127.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python 时间序列分解案例——加法分解seasonal_decompose

文章目录一、模型简介1.1 加法分解模型1.2 乘法分解模型1.3 分析步骤二、案例2.1 背景 & 数据 & python包2.2 分析过程一、模型简介 1.1 加法分解模型 加法分解模型适用于随着时间推移趋势和季节性变化不断累加&#xff0c;并且随机波动比较稳定的时间序列数据。该模…

初识linux之线程互斥

目录 一、线程互斥的概念 1. 多线程下全局数据的安全问题 2 线程互斥相关背景概念 二、线程加锁 1. 锁生成和销毁 2. 对一个锁加锁 3. 对一个锁解锁 三、解决多线程并发式访问临界资源问题 四、如何看待锁 1. 锁限制线程串行访问 2. 加锁和解锁的原子性 五、对锁进…

数学体操之牛顿数值法解方程的程序和图解

牛顿法是一种用来寻找函数零点的迭代方法&#xff0c;它基于以下思路&#xff0c;如果我们知道了一个函数在某个点的切线&#xff0c;那么函数的零点就可以通过切线与x轴的交点来近似计算。 给定一个函数,找到零点,过程如下: 选择初始点,然后使用这个点处的切线来近似,也就是…

java超详细的jvm调优

JVM调优 看这篇博客之前&#xff0c;可以先看我另外两篇 Java虚拟机&#xff08;Jvm详解&#xff09; Java垃圾回收机制(后续更新) 下面主要从以下几个方面进行展开描述&#xff1a; JVM实践调优主要步骤分析GC日志堆内存与元空间优化线程堆栈优化堆内存内部优化&#xff…

软件质量保证与软件测试 第五周(数据流测试)+第六周(集成测试开了个头)

数据流测试 1 定义/使用测试 一些概念的定义 例题理解概念 例子1&#xff1a; 定义清除的理解&#xff1a;就是说&#xff0c;如果路径上又遇到了其他定义节点&#xff0c;那就不是。 例子2&#xff1a; 第一步&#xff1a;先画程序图&#xff1a; 第二步&#xff1a;再…

什么是 AWS Lambda 冷启动问题?

什么是 AWS Lambda 冷启动问题&#xff1f; AWS Lambda 是一个无服务器计算平台&#xff0c;使开发人员能够快速构建和部署应用程序&#xff0c;而无需管理任何底层基础设施。但是&#xff0c;这种便利性也带来了一个缺点&#xff0c;即 AWS Lambda 冷启动问题。由于冷启动问题…

sgg第二天Java的语法

关键字 关键字(keyword)的定义和特点 定义&#xff1a;被Java语言赋予了特殊含义  特点&#xff1a;关键字中所有字母都为小写  注意,关键字不能被用作标识符&#xff01; 保留字 Java保留字&#xff1a;现有Java版本尚未使用&#xff0c;但以后版本可能会作为关键字使 …

Qt Quick - 弹出控件综述

Qt Quick - 弹出控件综述一、概述一、抽屉控件二、菜单控件三、弹出控件四、工具提示控件一、概述 控件功能Dialog带有标准按钮和标题的弹出式对话框&#xff0c;用于与用户进行短期交互Drawer可以用滑动手势打开和关闭的侧面板Menu弹出式菜单&#xff0c;可以用作上下文菜单或…

springboot事务

对于从事 java 开发工作的同学来说&#xff0c;spring 的事务肯定再熟悉不过了。 在某些业务场景下&#xff0c;如果一个请求中&#xff0c;需要同时写入多张表的数据。为了保证操作的原子性&#xff08;要么同时成功&#xff0c;要么同时失败&#xff09;&#xff0c;避免数据…

设备是如何实现延时关机的

文章目录1. 引言2. 延时关机的实现方式2.1 自建定时服务实现2.2 RocketMQ中间件实现2.2.1 生成端demo2.2.2 消费端demo3. 结尾1. 引言 在设备联动中&#xff0c;有些场景需要保持设备继续工作一段时间再关机。比如在厨房场景下&#xff0c;存在燃气灶和烟机的联动场景&#xf…

基于kettle部署图形化界面(spoon)

最近使用kettle部署windows&#xff0c;mac、linux服务遇到的坑做一个总结。 1、mac、linux部署&#xff1a; 1⃣️拉取docker镜像 docker pull hiromuhota/webspoon 2⃣️创建并运行docker容器 docker run -d -p 8080:8080 hiromuhota/webspoon --name webspoon --restar…

HTML:彩虹按钮

彩虹按钮&#xff08;盗版按钮&#xff0c;B站仿写&#xff0c;略有不同&#xff01;&#xff09; 链接 <html><head><title>demo</title><style>*{margin: 0;padding: 0;}body{display: flex;justify-content: center;align-items: center;…

【hello Linux】Linux软件管理器yum

目录 1.Linux软件管理器yum 1.1 关于lrzsz 1.2 使用yum时的注意事项 1.3 查看软件包&#xff1a;yum list 1.4 安装软件&#xff1a;yum install 1.5 卸载软件&#xff1a;yum remove 1.6 更新yum源 1.7 实战项目 Linux&#x1f337; 1.Linux软件管理器yum 在windows系统下有应…

交友项目【查询黑名单人员,移除黑名单人员】功能实现

目录 1&#xff1a;交友项目 1.1&#xff1a;查询黑名单人员 1.1.1&#xff1a;接口地址 1.1.2&#xff1a;流程分析 1.1.2&#xff1a;代码实现 1.2&#xff1a;移除黑名单人员 1.2.1&#xff1a;接口地址 1.2.2&#xff1a;流程分析 1.2.3&#xff1a;代码实现 1&am…

【LeetCode每日一题: 1039. 多边形三角剖分的最低得分 | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】

&#x1f34e;作者简介&#xff1a;硕风和炜&#xff0c;CSDN-Java领域新星创作者&#x1f3c6;&#xff0c;保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享&#x1f48e;&#x1f48e;&#x1f48e; &#x1f34e;座右…

0416 leetcode每日一题 1042. 不邻接植花

题目描述&#xff1a; 力扣 思路&#xff1a; 从题目描述中可知&#xff0c;花的种类一共有四种&#xff0c;且一定有满足题意的答案。 可以首先将所有花园中的花设置为0&#xff0c;然后遍历与其相邻的花园&#xff0c;选择没有使用过的花的种类&#xff08;1 2 3 4&#xf…

【ChatGPT】阿里版 ChatGPT 突然官宣意味着什么?

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 阿里版 ChatGPT 突然官宣 ​ ChatGPT 技术在 AI 领域的重要性 自然语言生成 上下文连续性 多语言支持 ChatGPT 未来可能的应用场景 社交领域 商业领域 ​编辑 医疗领域…

LeetCode_单调栈_中等_1019.链表中的下一个更大节点

目录1.题目2.思路3.代码实现&#xff08;Java&#xff09;1.题目 给定一个长度为 n 的链表 head。对于列表中的每个节点&#xff0c;查找下一个更大节点的值。也就是说&#xff0c;对于每个节点&#xff0c;找到它旁边的第一个节点的值&#xff0c;这个节点的值严格大于它的值…

Vue项目创建流程

一、安装Vue和查看Vue版本 1.1安装Vue npm i -g @vue/cli1.2 查看Vue Vue -V二、新建一个Vue项目 2.1 使用命令创建项目 vue create vue-project # vue-project是项目名称Default 表示使用默认配置,默认勾选babel、eslint ,回车之后直接进入装包 Manually 自定义勾选特性…

Vector - CAPL - CAN x 总线信息获取(续2)

继续.... 目录 ErrorFrameCount -- 错误帧数量 代码示例 ErrorFrameRate -- 错误帧速率 代码示例 ExtendedFrameCount -- 扩展帧数量 代码示例 ExtendedFrameRate -- 扩展帧速率 代码示例 ExtendedRemoteFrameCount -- 远程扩展帧数量 代码示例 ExtendedRemoteFrameRa…