Java实现异步的4种方式

news2024/11/18 0:00:08

文章目录

  • 异步
    • 1、Future与Callable
    • 2. CompletableFuture
    • 3. Spring框架的异步支持
        • 3.1 启动类开启对Async的支持 @EnableAsync
        • 3.2 配置自定义线程池
        • 3.3 异步业务
        • 3.4 调用异步业务方法
    • 4. 使用消息队列
        • 4.1 安装RabbitMq
        • 4.2 使用
        • 4.3 MQ消息丢失以及重复消费问题
    • 5、总结

异步

异步(Asynchronous)是指在进行多任务处理时,各个任务的执行不依赖于其他任务的完成,无需等待一个操作完成后再开始下一个操作。与之相对的是同步(Synchronous),同步操作需要按顺序执行,每个步骤必须等待前一个步骤完成才能开始。

异步处理的优点包括但不限于:

  1. 提高效率:允许程序在等待某个慢操作(如I/O操作)完成的同时,继续执行其他任务,提高了系统的整体响应速度和吞吐量。
  2. 增强用户体验:在用户界面(UI)编程中,异步处理能防止界面冻结,保持应用的响应性。
  3. 解耦:通过事件驱动或消息队列的方式,异步处理有助于解耦系统组件,使它们可以独立地开发、部署和扩展。
  4. 可扩展性:对于大规模分布式系统,异步通信机制能够更容易地水平扩展,以应对高并发场景。

实现异步编程的技术和框架有很多,根据不同的应用场景和技术栈选择合适的方法,例如:

  • 回调函数:是最基础的异步处理方式,通过传入一个函数作为参数,在异步操作完成时调用该函数。
  • Promise/Promise链(JavaScript中)或Future(Java中):提供了更加优雅的异步编程模型,可以链式调用来组织异步操作。
  • async/await(现代编程语言中广泛支持):进一步简化异步代码,使得异步代码看起来更像是同步代码,提高可读性和可维护性。
  • 消息队列和事件总线:用于解耦系统组件,通过发布-订阅模式或命令模式处理异步消息。
  • 线程池和并发库:如Java的Executor框架,用于管理线程资源,执行异步任务。

选择合适的异步处理策略,可以显著提升软件系统的性能和用户体验。

在这里插入图片描述

1、Future与Callable

Java并发包中的FutureCallable接口提供了基本的异步编程模型。你可以通过ExecutorService提交一个实现了Callable的任务,它会返回一个Future对象。你可以在这个Future对象上调用get()方法来获取结果,这个方法会阻塞直到结果可用。

Java

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class AsyncExample {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        
        Callable<String> task = () -> {
            Thread.sleep(2000); // 模拟耗时操作
            return "Task completed!";
        };
        
        Future<String> future = executor.submit(task);
        
        System.out.println("Doing something else...");
        
        // 非阻塞方式检查结果是否准备好了
        while (!future.isDone()) {
            Thread.sleep(100);
            System.out.println("Waiting for result...");
       }
        
        System.out.println(future.get()); // 获取并打印结果
       
        executor.shutdown();
    }
}

2. CompletableFuture

从Java 8开始,CompletableFuture为异步编程提供了一个更强大、灵活的API,支持链式调用、组合多个异步操作以及更复杂的异步控制流。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class AsyncExampleWithCompletableFuture {
    public static void main(String[] args) {
        CompletableFuture.supplyAsync(() -> {
            sleep(2000); // 模拟耗时操作
           return "Hello";
        }).thenAccept(result -> System.out.println("Result: " + result));
        
        System.out.println("Doing something else concurrently...");
    }
    
    private static void sleep(int millis) {
        try {
           Thread.sleep(millis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

3. Spring框架的异步支持

如果你的项目使用了Spring框架,Spring提供了对异步方法的直接支持。你只需要用@Async注解标记希望异步执行的方法,并配置一个异步任务执行器(TaskExecutor)。

3.1 启动类开启对Async的支持 @EnableAsync
@SpringBootApplication
@EnableScheduling
@EnableAsync
@MapperScan("com.example.demo.dao")
public class SpringBoot3DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBoot3DemoApplication.class, args);
    }

}
3.2 配置自定义线程池
@Configuration
public class AsyncConfig {
    @Bean(name = "myAsyncThreadPool")
    public ThreadPoolTaskExecutor asyncThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // 核心线程数
        executor.setMaxPoolSize(10); // 最大线程数
        executor.setQueueCapacity(200); // 队列大小
        executor.setThreadNamePrefix("Async-"); // 线程前缀名
        executor.initialize();
        return executor;
    }
}
3.3 异步业务
@Service
@Slf4j
public class AsyncService {
    @Async("myAsyncThreadPool")
    public void asyncMethod1() {
        log.info("asyncMethod1 start");
        try {
            //发送短信...
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("发送短信 成功");
    }
    @Async("myAsyncThreadPool")
    public void asyncMethod2() {
        log.info("asyncMethod2 start");
        try {
            //通知物流...
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("通知物流 成功");
    }
}
3.4 调用异步业务方法
@Slf4j
@RestController
@Tag(name = "测试控制器")
@RequestMapping("test")
public class TestController {

    @Resource
    private AsyncService asyncService;

    @Operation(summary = "下单")
    @PostMapping("placeAnOrder")
    public CommonResult<String> placeAnOrder() {
        // 主线程-》参数校验、扣减库存、优惠券状态更新、创建订单
        // 异步线程1-》发送短信
        asyncService.asyncMethod1();
        // 异步线程2-》通知物流
        asyncService.asyncMethod2();
        return CommonResult.SUCCESS("下单成功");
    }
}

4. 使用消息队列

对于更复杂的异步处理需求,特别是需要跨服务通信或解耦不同服务组件的情况,可以考虑引入消息队列(如RabbitMQ、Kafka等)。通过发布-订阅模式或点对点模式,将任务放入队列,由专门的消费者异步处理。

4.1 安装RabbitMq

Linux下载安装 RabbitMQ

win10下安装 RabbitMQ

4.2 使用

RabbitMQ快速上手以及RabbitMQ交换机的四种模式

4.3 MQ消息丢失以及重复消费问题

RabbitMQ解决消息丢失以及重复消费问题

5、总结

总结每种方案的选择取决于具体的应用场景、复杂度和性能要求。简单的异步任务可能仅需使用FutureCallable,而复杂的异步流程控制和跨服务通信则可能更适合采用CompletableFuture或消息队列。

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

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

相关文章

vue3 调用本地exe

1、注册表注册 在注册表中直接按照图2注册数据&#xff1b;也可以按照图3注册表的文件创建文档&#xff0c;然后点击打开&#xff0c;将会将注册表写入window系统。 图2 Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\F1] "URL:F1 Protocol Handler" &q…

Ansible03-Ansible Playbook剧本详解

目录 写在前面5. Ansible Playbook 剧本5.1 YAML语法5.1.1 语法规定5.1.2 示例5.1.3 YAML数据类型 5.2 Playbook组件5.3 Playbook 案例5.3.1 Playbook语句5.3.2 Playbook1 分发hosts文件5.3.3 Playbook2 分发软件包&#xff0c;安装软件包&#xff0c;启动服务5.3.3.1 任务拆解…

通过ESP32芯片模组实现产品智能化升级,启明云端乐鑫代理商

随着科技的不断进步&#xff0c;物联网&#xff08;IoT&#xff09;已经渗透到我们生活的方方面面&#xff0c;成为现代生活不可或缺的一部分。在这场智能化革命中&#xff0c;乐鑫科技以其创新的ESP32芯片模组&#xff0c;为智能家居和智能设备的发展注入了新的活力。作为乐鑫…

一次绕过waf进行xss的经历

今天室友遇到一个好玩的网站&#xff0c;下面是一些尝试绕过Waf进行XSS的记录。首先该网站没有对左右尖号和单双引号做任何过滤或转义。且有未知的waf或者其他阻止恶意访问的手段。 首先我的访问为 login.asp?f1 时候&#xff0c;页面关键源码为 可能是表示登录次数的一个东西…

简单模拟实现shell(Linux)

目录​​​​​​​ 前言 展示效果 实现代码 前言 该代码模拟了shell的实现&#xff0c;也就是解析类似于“ls -a -l"的命令&#xff0c;当我们启动我们自己写的shell的可执行程序时&#xff0c;我们输入"ls"的命令&#xff0c;也可以展示出在shell中输入&…

广告联盟收款的解决方案

目前国内的affiliate&#xff0c;收海外联盟款就六种主要的解决方案(使用何种方式收款&#xff0c;不是我们决定的&#xff0c;是你操作的联盟决定的&#xff0c;你要根据联盟的要求提供相应的收款方式) 1 直接注册国外当地的银行账户 比如我收美国的广告联盟佣金用的是我美国银…

【设计模式】JAVA Design Patterns——Dependency Injection(依赖注入模式)

&#x1f50d;目的 依赖注入是一种软件设计模式&#xff0c;其中一个或多个依赖项&#xff08;或服务&#xff09;被注入或通过引用传递到一个依赖对象&#xff08;或客户端&#xff09;中&#xff0c;并成为客户端状态的一部分。该模式将客户的依赖关系的创建与其自身的行为分…

Java集合—TreeSet和TreeMap

一、TreeSet 1.当使用无参构造器&#xff0c;创建TreeSet时&#xff0c;仍然是无序的。 2.若希望添加的元素有序&#xff0c;需要使用TreeSet提供的构造器,传入一个比较器。 该比较器是一个接口&#xff0c;里面有一个方法叫compare()&#xff0c;传入一个实现该接口的类(匿名内…

使用PyAutoGUI识别PNG图像并自动点击按钮

在自动化测试、任务批处理等场景中,我们常常需要控制GUI程序的鼠标键盘操作。PyAutoGUI就是一个非常方便的Python模块,可以帮助我们实现这些操作。今天我们就来看看如何使用PyAutoGUI识别屏幕上的PNG图像,并自动点击图像所在位置。 C:\pythoncode\new\autoguirecongnizepng.py …

树--搜索二叉树

现有一棵结点数目为n的二叉树&#xff0c;采用二叉链表的形式存储。对于每个结点均有指向左右孩子的两个指针域&#xff0c;而结点为n的二叉树一共有n-1条有效分支路径。那么&#xff0c;则二叉链表中存在2n-(n-1)n1个空指针域。那么&#xff0c;这些空指针造成了空间浪费。 例…

Redis 中 Set 数据结构详解

用法 Redis 中的 Set 是一个无序&#xff0c;不重复集合&#xff08;里面的元素为字符串&#xff09;&#xff0c;支持常用的集合操作。 常见命令 1. 增 添加一个或多个元素到 set 中 SADD key member [ member ... ] 返回值&#xff1a; 添加成功的元素个数 将一个元素移到…

react跨组件通信Context

案例&#xff1a;现在有个父-子-孙组件 需要进行组件通信 import { useState } from "react"; // 创建上下文 const CountContext React.createContext();//子组件 const SonComponent (props) > {return (<div><h2>子组件</h2><Grandson…

spdlog 使用

spdlog 是一个日志库&#xff0c;直接引用头文件即可使用&#xff0c;速度快&#xff0c;异步打印日志。 对应的git地址 spdloggit地址 对应的目录 把上面划线的文件夹引入到自己的工程中&#xff0c;即可使用spdlog 下面是使用例子 inline static void create_logging(const…

LeetCode hot100-57-G

17. 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。不会&#xff0c;放IDEA里执行了一下大概理解了流程 …

Django序列化器中validate没起作用?validate的触发时机

今天上班的时候分配了一个任务&#xff0c;是修复前端的一个提示优化&#xff0c;如下图所示&#xff1a; 按照以往的经验我以为可以直接在validate上进行校验&#xff0c;如何抛出一个异常即可 &#xff0c;例如&#xff1a; class CcmSerializer(serializers.ModelSerialize…

划重点来了,计算机组成原理之计算机存储介绍与汉明码纠错

存储器 1. 分类 &#xff08;1&#xff09;按存储介质分类&#xff1a; 存储介质是能寄存”0“或"1"两种代码的物质或元器件。 包括半导体器件&#xff0c;磁性材料&#xff0c;光盘等。 半导体存储器&#xff1a;半导体器件组成的存储器。断电后数据会丢失&…

关于Word目录的更新

左侧标题顺序如有调整&#xff0c;自动目录并不会同步更新&#xff0c;每次都要记得在正文目录左上角点击更新目录

【Linux终端探险】:从入门到熟练,玩转基础命令的秘密(一)

文章目录 &#x1f680;Linux基础命令⭐1. 查看目录命令&#x1f4a5;2. 切换目录&#x1f44a;3. 创建目录❤️4. 删除目录/文件&#x1f6b2;5. 修改目录/文件&#x1f308;6. 拷贝目录/文件 &#x1f680;Linux基础命令 ⭐1. 查看目录命令 在Linux中&#xff0c;查看目录的…

【Paddle】Inplace相关问题:反向传播、影响内存使用和性能

【Paddle】Inplace相关问题&#xff1a;反向传播、影响内存使用和性能 写在最前面inplace 的好处有哪些&#xff1f;能降低计算复杂度吗在反向传播时&#xff0c;Inplace为什么会阻碍呢&#xff1f;“计算图的完整性受损”表达有误原地操作 sin_()为什么原地操作会阻碍反向传播…

【AIGC】GPT-4o技术分析-浅谈

GPT-4o&#xff1a;人工智能技术的全新里程碑 一、引言二、GPT系列版本间的对比分析三、GPT-4o的技术能力分析多模态处理能力速度与性能优化情感理解与表达能力 四、个人整体感受五、结语 一、引言 在人工智能技术的浪潮中&#xff0c;OpenAI再次以其卓越的创新能力引领潮流。近…