优化耗时业务:异步线程在微服务中的应用

大家好,我是程序员大猩猩。

大家都知道,在我们实际开发过程中,我们经常会遇到一些耗时的业务和逻辑,比如说要上传什么大文件,又或者是大文件的数据处理。我们不能一个接口上等着这些耗时任务完成之后了,再返回,那用户体验度会大打折扣的。

这时候,我们最基本的操作就是使用多线程处理或者是异步线程处理。这里我们说一下异步线程处理。

那么我们来说一下,微服务中如何使用异步线程呢?

一、使用 @Async 注解我们来看看它的源码:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
  /**
   * A qualifier value for the specified asynchronous operation(s).
   * <p>May be used to determine the target executor to be used when executing
   * the asynchronous operation(s), matching the qualifier value (or the bean
   * name) of a specific {@link java.util.concurrent.Executor Executor} or
   * {@link org.springframework.core.task.TaskExecutor TaskExecutor}
   * bean definition.
   * <p>When specified on a class-level {@code @Async} annotation, indicates that the
   * given executor should be used for all methods within the class. Method-level use
   * of {@code Async#value} always overrides any value set at the class level.
   * @since 3.1.2
   */
  String value() default "";
}

我们看到Async内,只有一个参数value,这个value的设置来确定异步线程指定线程池的名字。

当然这里我们可以不设置这个value,可以使用默认的。但是为什么要设置这个value,来指定线程池呢?因为指定线程是为了控制和管理异步任务。

a. 如果不指定线程池,Spring 默认使用 SimpleAsyncTaskExecutor,这不是一个真正的线程池,因为它为每个任务创建一个新的线程。这可能导致线程数量的快速增长,从而消耗大量系统资源。通过指定一个真正的线程池,如 ThreadPoolTaskExecutor,可以复用线程,减少资源消耗。b. 线程池可以提供更好的性能,因为它可以减少线程创建和销毁的开销。线程池中的线程可以被重复使用,而不是每次执行异步任务时都创建新的线程。

c. 通过为不同的服务或组件指定不同的线程池,可以实现线程隔离。这意味着如果一个服务出现异常或者需要大量时间来处理任务,它不会影响到其他服务的性能。d. 线程池提供了任务调度和管理的能力,比如设置核心线程数、最大线程数、队列容量等,这样可以更精细地控制任务的执行行为。e. 线程池通常提供了任务执行错误的处理机制,比如当任务执行失败时的重试策略。f. 线程池可以提供线程的运行状态和性能指标,这对于监控和调试应用程序是非常有用的。怎么设置线程池?

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class ThreadPoolConfig {
    @Bean(name = "taskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2); // 核心线程数
        executor.setMaxPoolSize(5); // 最大线程数
        executor.setQueueCapacity(10); // 队列容量
        executor.setThreadNamePrefix("Async-"); // 线程名称前缀
        executor.initialize();
        return executor;
    }
}

设置好线程池后,我们就可以在方法上使用@Async,开启异步线程了。

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

最后要记住:在微服启动类之上,加入注释@EnableAsync就可以了。

@SpringBootApplication
@EnableAsync
public class AsyncApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class, args);
    }
}

二、使用 CompletableFuture

CompletableFuture 是 Java 8 引入的一个类,用于表示异步计算的结果。通过 CompletableFuture,我们可以很方便地实现异步操作,并且可以链式调用多个异步任务。

@Service
public class CompletableFutureService {
    public CompletableFuture<String> executeAsyncTask() {
        return CompletableFuture.supplyAsync(() -> {
            System.out.println("执行异步任务:" + Thread.currentThread().getName());
            return "异步任务执行结果";
        });
    }
}

@RestController
public class CompletableFutureController {
    @Autowired
    private CompletableFutureService completableFutureService;
    @GetMapping("/completableFuture")
    public CompletableFuture<String> completableFuture() {
        return completableFutureService.executeAsyncTask();
    }
}三、组合使用 @Async 和 Future

我们可以通过 @Async 返回一个 Future 对象,以便在需要时获取异步任务的执行结果。

@Service
public class FutureService {

    @Async
    public Future<String> executeAsyncTask() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("执行异步任务:" + Thread.currentThread().getName());
        return new AsyncResult<>("异步任务执行结果");
    }
}

@RestController
public class FutureController {

    @Autowired
    private FutureService futureService;

    @GetMapping("/future")
    public String future() throws ExecutionException, InterruptedException {
        Future<String> future = futureService.executeAsyncTask();
        return "异步任务执行结果:" + future.get();
    }
}

本文介绍了在SpringBoot中使用异步线程的三种方式:使用@Async注解、CompletableFuture和@Async结合Future。在实际开发中,我们可以根据具体需求选择合适的异步实现方式,提高应用程序的性能和用户体验。

相关推荐
不写八个7 分钟前
Python办公自动化教程(005):Word添加段落
开发语言·python·word
IT学长编程7 分钟前
计算机毕业设计 Java酷听音乐系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·音乐系统·计算机毕业设计选题
HEX9CF11 分钟前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
IT学长编程25 分钟前
计算机毕业设计 基于协同过滤算法的个性化音乐推荐系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·毕业论文·协同过滤算法·计算机毕业设计选题·个性化音乐推荐系统
小小娥子29 分钟前
Redis的基础认识与在ubuntu上的安装教程
java·数据库·redis·缓存
DieSnowK31 分钟前
[Redis][集群][下]详细讲解
数据库·redis·分布式·缓存·集群·高可用·新手向
赵荏苒36 分钟前
Python小白之Pandas1
开发语言·python
几何心凉37 分钟前
已解决:org.springframework.web.HttpMediaTypeNotAcceptableException
java
丶Darling.38 分钟前
代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作&&删除二叉搜索树中的节点&&修剪二叉搜索树
开发语言·数据结构·c++·笔记·学习·算法
华农第一蒟蒻39 分钟前
Java中JWT(JSON Web Token)的运用
java·前端·spring boot·json·token