首页 > 其他分享 >【无标题】

【无标题】

时间:2024-09-18 22:25:17浏览次数:10  
标签:异步 处理 无标题 任务 Future CompletableFuture 线程

Spring的异步任务

@Async 注解用于标注一个方法为异步执行。当调用这个方法时,Spring 会启动一个新线程来执行该方法,而调用者不必等待其执行完成。通过 @EnableAsync 注解启用 Spring 的异步功能。这个注解通常标注在配置类上。

异步方法可以返回

  1. void类型
  2. Future<T>类型:用于返回异步方法的结果,future.get()会阻塞,直到任务执行完成
  3. CompletableFuture<T>支持更多的异步编排操作

异步任务的线程池管理

默认线程池:Spring 使用默认的 SimpleAsyncTaskExecutor,但该实现不是真正的线程池,而是每次创建新线程。更常用的是使用 ThreadPoolTaskExecutor 来配置自定义线程池。

自定义线程池:可以通过配置类自定义线程池,实现更好的线程管理和任务调度。

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean(name = "customExecutor")
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("AsyncThread-");
        executor.initialize();
        return executor;
    }
}

使用自定义线程池:

@Async("customExecutor")
public void asyncMethod() {
    // 异步任务逻辑
}

异步任务的异常处理

默认行为:异步方法中的异常不会自动被抛出到调用者。

处理方式

  1. 可以使用 CompletableFutureexceptionallyhandle 方法处理异常。

  2. 还可以配置 AsyncUncaughtExceptionHandler 来处理没有返回值的异步任务中的异常。

@Async
public CompletableFuture<String> asyncMethodWithException() {
    try {
        // 业务逻辑
        return CompletableFuture.completedFuture("Task Completed");
    } catch (Exception e) {
        return CompletableFuture.failedFuture(e);
    }
}

// 全局异常处理
@Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
        System.out.println("Exception in async method: " + throwable.getMessage());
    }
}

异步方法的调用方式

内部调用的问题:如果一个类中的异步方法被同类的其他方法调用,由于 Spring 的代理机制,异步方法不会以异步方式执行。必须从外部调用。

面试问题

  • 为什么同类内部调用 @Async 标注的方法不会生效?
  • 如何解决同类内部调用异步方法的问题?
解释:

当类内调用时,Spring 不能通过代理对象来拦截和处理异步方法,所以异步特性失效。解决方案是通过 外部类 调用,或者使用 Spring AOP

异步任务的超时控制

  • 超时设置:可以通过 @Async 中的 Future 返回类型,结合 future.get(timeout, TimeUnit) 来设置超时,或者通过线程池配置来控制任务的超时。
  • 面试问题:
    • 如何为异步任务设置超时?
    • 如何在 Spring 异步任务中处理超时异常?
示例:
Future<String> future = asyncMethod();
try {
    String result = future.get(5, TimeUnit.SECONDS);  // 设置超时
} catch (TimeoutException e) {
    // 处理超时
}

并行任务和批量处理

  • 多个异步任务并行执行:可以使用 CompletableFuture.allOf() 来并行处理多个任务,并在所有任务完成后执行后续逻辑。
  • 面试问题:
    • 如何并行执行多个异步任务并等待它们完成?
并行执行示例:
CompletableFuture<String> task1 = asyncMethod1();
CompletableFuture<String> task2 = asyncMethod2();
CompletableFuture<String> task3 = asyncMethod3();

CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2, task3);
allTasks.thenRun(() -> {
    // 所有任务完成后的操作
});

使用 @Async 的注意事项

  • 异步方法必须是 public 的,且不能是 static,否则 Spring 无法代理。
  • 异步方法必须返回 voidFutureCompletableFuture 类型,如果返回其他类型,将不会异步执行。
  • @Async 的方法执行时间应较长,适用于异步场景。如果任务非常短暂,则不建议使用 @Async,可能会因为线程创建和销毁而带来性能开销。

性能调优与监控

  • 线程池调优:在高并发场景下,需要合理配置线程池的大小、队列容量以及拒绝策略,以确保系统的吞吐量和稳定性。
  • 监控和优化:可以通过 Spring Actuator 监控线程池的状态,包括线程数量、队列长度、任务完成时间等。结合 JMX 或其他监控工具来优化异步任务执行性能。
  • 面试问题:
    • 如何监控异步任务的执行情况?
    • 如何调优异步任务的线程池配置?

CompletableFutureFuture 有什么区别?

CompletableFutureFuture 都是用于处理异步操作的接口,但 CompletableFuture 提供了更多功能和更强大的异步编排能力。以下是它们的主要区别:

非阻塞 VS 阻塞
  • Future:当你调用 future.get() 方法时,当前线程会阻塞,直到异步任务完成。如果任务执行时间较长,调用线程会一直等待。
  • CompletableFuture:可以以非阻塞的方式处理异步任务,提供了多种回调函数,例如 thenApply(), thenAccept() 等,允许任务完成后自动执行后续操作,无需阻塞等待。

示例

// Future 阻塞
Future<String> future = executorService.submit(() -> "Task Result");
String result = future.get();  // 阻塞等待,直到任务完成

// CompletableFuture 非阻塞
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Task Result");
completableFuture.thenAccept(result -> {
    // 任务完成后的回调,不阻塞
    System.out.println("Result: " + result);
});
组合与链式调用
  • Future:不能将多个 Future 任务组合在一起,也不能通过链式方式将任务依次执行。每次调用 future.get() 时,都会阻塞,必须等待结果。
  • CompletableFuture:支持任务之间的组合和链式调用。可以通过 thenApply(), thenCompose(), thenCombine() 等方法将多个异步任务进行组合,实现复杂的任务编排。

示例

// 使用 CompletableFuture 进行任务链式调用
CompletableFuture.supplyAsync(() -> "Hello")
    .thenApply(result -> result + " World")
    .thenAccept(System.out::println);  // 输出 "Hello World"
手动完成
  • FutureFuture 是由任务的执行者(通常是 ExecutorService)完成的,调用者不能手动完成它。
  • CompletableFutureCompletableFuture 提供了手动完成的方法,如 complete(), completeExceptionally(),可以在任务执行过程中或之后手动设置结果或异常。

示例

CompletableFuture<String> completableFuture = new CompletableFuture<>();
completableFuture.complete("Manual completion");  // 手动完成
异常处理
  • Future:如果任务执行过程中发生异常,future.get() 会抛出 ExecutionException,没有更灵活的异常处理机制。
  • CompletableFuture:提供了更强大的异常处理机制,可以使用 exceptionally()handle() 方法来处理任务执行中的异常,并进行恢复操作。

示例

CompletableFuture.supplyAsync(() -> {
    throw new RuntimeException("Error");
}).exceptionally(ex -> {
    System.out.println("Exception: " + ex.getMessage());
    return "Recovered";
}).thenAccept(System.out::println);  // 输出 "Recovered"
支持并行任务组合
  • FutureFuture 不能直接用于组合多个异步任务。要处理多个 Future,通常需要手动管理线程或者使用工具类(如 ExecutorCompletionService)。
  • CompletableFuture:可以通过 allOf()anyOf() 方法并行执行多个任务,并在所有任务完成或任意一个任务完成时触发后续操作。

示例

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Task 1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Task 2");

// 并行执行两个任务,等待它们都完成
CompletableFuture.allOf(future1, future2).thenRun(() -> {
    System.out.println("All tasks completed");
});
异步回调编排
  • Future:没有直接支持异步回调的功能。通常需要手动轮询或者阻塞获取结果。
  • CompletableFuture:支持多种异步回调,例如 thenApplyAsync(), thenAcceptAsync() 等,可以轻松实现非阻塞的异步回调操作。

示例

CompletableFuture.supplyAsync(() -> "Task")
    .thenApplyAsync(result -> result + " Completed")
    .thenAcceptAsync(System.out::println);  // 异步回调执行
异步处理多个任务
  • Future:要处理多个异步任务时,Future 需要手动协调各个任务,不能灵活地进行组合或处理。
  • CompletableFuture:支持多个任务的组合,比如两个任务并行执行并将结果组合,或一个任务的结果作为下一个任务的输入。使用 thenCombine(), thenCompose() 等方法可以处理复杂的任务流。

示例

CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> "Task 1");
CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> "Task 2");

// 合并两个任务的结果
task1.thenCombine(task2, (result1, result2) -> result1 + " & " + result2)
     .thenAccept(System.out::println);  // 输出 "Task 1 & Task 2"
功能拓展
  • Future:是 Java 5 引入的基本异步接口,功能比较有限,主要用于简单的异步任务执行。
  • CompletableFuture:是 Java 8 引入的增强版异步处理工具,支持更复杂的异步编排和并行处理。除了继承 Future 的功能外,还提供了更多高级特性。

总结:

  • Future 适合简单的异步任务提交和阻塞获取结果,功能有限。
  • CompletableFuture 是更加强大、灵活的工具,支持非阻塞的任务执行、异步回调、任务组合、异常处理等复杂场景,是处理现代异步编程的首选。
面试问题示例:
  1. FutureCompletableFuture 有什么区别?
  2. 在什么情况下使用 CompletableFuture 优于 Future
  3. 如何处理 CompletableFuture 中的异常?
  4. 如何使用 CompletableFuture 实现多个异步任务的并行处理?

1. FutureCompletableFuture 有什么区别?

  • Future 是 Java 5 引入的异步结果容器,主要用于简单的异步任务,它需要调用 get() 方法阻塞等待结果。
  • CompletableFuture 是 Java 8 引入的扩展版,支持链式任务、非阻塞操作、异步回调、任务组合以及更强的异常处理机制,允许更加灵活地处理异步任务。

2. 在什么情况下使用 CompletableFuture 优于 Future

  • 当我们需要非阻塞的异步操作异步回调,或者组合多个异步任务时,CompletableFuture 更加合适。它支持链式任务执行、异步结果处理,并且能更方便地处理异常和组合任务。

3. 如何处理 CompletableFuture 中的异常?

  • CompletableFuture 提供了 exceptionally()handle() 等方法,用于捕获并处理任务中的异常。例如,exceptionally() 可以在出现异常时提供默认值或执行恢复操作,handle() 可以同时处理成功结果和异常。

4. 如何使用 CompletableFuture 实现多个异步任务的并行处理?

  • 可以使用 CompletableFuture.allOf() 来并行执行多个异步任务,等待所有任务完成后继续执行;也可以使用 thenCombine() 来合并两个任务的结果。这样可以有效实现任务的并行处理并合并结果。

标签:异步,处理,无标题,任务,Future,CompletableFuture,线程
From: https://blog.csdn.net/qq2501055281/article/details/142320952

相关文章

  • 【无标题】
    系列文章目录提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加例如:第一章Python机器学习入门之pandas的使用提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录系列文章目录前言一、pandas是什么?二、使用步骤1.引入库2.读入数据......
  • 【无标题】高等数学
     第一章 函数与极限    第一节 映射与函数       一、集合          1.集合概念            集合是数学中的一个基本概念,我们先通过例子来说明这个概念。例如,一个书柜中的书构成一个集合,一间教室......
  • 【无标题】摩羯台风来袭:自然界的力量,人类的应对与坚韧
    摩羯台风,这是一个令人畏惧的自然力量的名字,也是近年来频繁出现的台风之一。每当摩羯台风登陆,无论是在大陆还是岛屿,都会带来强烈的风雨和破坏性的影响。而且,摩羯台风往往伴随着巨大的海浪和潮汐,给沿海地区带来了巨大的灾害。为什么摩羯台风的威力如此之大?首先,摩羯台风的风速非......
  • 【无标题】
    单选题第11/60题自动跳下一题0以下哪份代码可以实现下图Grid布局A.通过设置不同Gridltem的宽度//xxx.ets@Entry@ComponentstructGridExample3{numbers:String[]■['0','1','2','3','4','5','6','7','......
  • 【无标题】
    第60/60题一个应用通常会包含多种功能,将不同的功能特性按模块米划分和管理是-种良好的设计方式。在开发过程中,我们可以将每个功能模块作为一个独立的Module进行开发,下面关于Module的说法正确的是口A.entry类型的Module,是应用的主模块,-个应用只能包含唯一--一个entry类......
  • 【无标题】
    文章目录DRBD9.26Anolisos8.9安装配置1、安装DRBD9.261.1安装epel源2、安装DRBD9.26后,重新编译内核添加对DRBD的内核支持3、配置DRBDDRBD9.26Anolisos8.9安装配置1、安装DRBD9.26两种安装方式1、添加epel-release源安装;2、源码编译安装。参考centosDRBD......
  • 【无标题】
     2024年奥运会的开幕式与2008年奥运会开幕式相比较。中国的元素、华夏民族的文化能够得到精彩的展现,无疑会极大地激发国人的民族自豪感和文化认同感。华夏民族文化博大精深,源远流长,涵盖了诗词歌赋、书法绘画、音乐舞蹈、戏曲杂技、建筑园林、服饰饮食等众多方面。这些文化......
  • 【[代码详细教程+文档+PPT+源码等]SSM框架美妆商城全套|电商购物[包运行成功+永久免费
    一、项目介绍《基于SSM美妆商城项目前后台全套》该项目含有源码、文档、答辩ppt、开题报告、代码详细讲解教程等资料、配套开发软件、软件安装教程、项目发布教程等前端使用技术:JSP,bootstrap、jQuery等后端使用技术:Springmvc、Spring、Mybatis等数据库:Mysql数据库二、......
  • 【无标题】考研数学强化阶段刷题建议
    ......
  • 【无标题】
    序列三儿子——元组1.元组的许多用法与列表相似,元组的二哥列表用[]标识,元组用()标识2.表示方法#标识a=(1,2)#元组用()标识,元素间用“,”隔开print(a)#如果元组中只有一个元素,末尾也必须添加逗号a=(1,)print(a)#判断变量类型用type()print(type(a))#输出<class'tup......