其他分享
首页 > 其他分享> > Spring中开发异步(@Async)

Spring中开发异步(@Async)

作者:互联网

我们是如何编写异步代码的

异步执行,相信很多同学都用过,比如向下面这么使用

// 最原始的方式,效率比较低
new Thread(() -> {
    // 执行任务
}).start();

// 线程池放到成员属性中,并管理了其生命周期
private ExecutorService executorService = Executors.newCachedThreadPool();
// 使用线程池的方式
executorService.execute(() -> {
    // 执行任务
});

第一种方式就不用说了,不建议这样使用。第二种方式可以用,但是还是比较麻烦:

Spring很好的帮我们解决了这些问题

Spring中何编写异步方法

在spring-context中给我们提供了两个注解

那么我们使用异步将会是很简单的2步:

  1. 告诉Spring开启异步, @EnableAsync 注解(在启动类,或者某一个spring的组件上加上这个注解)
  2. 在我们需要异步执行的方法上加上@Async

做完这2步我们就编写好了一个异步执行的方法,是不很简单。

使用异步要注意的一些问题

到此处Spring中使用异步算是比较完整的了,但是我们使用过线程池的同学都知道线程池是有很多参数的,怎么给@Async的线程池设置这些参数呢

定制线程池

Spring在我们未配置Executor时会个我们配置一个默认的ThreadPoolTaskExecutor可以参考Spring源代码:

	// TaskExecutionAutoConfiguration 源码
	@Lazy
	@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
			AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
	@ConditionalOnMissingBean(Executor.class)
	public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
		return builder.build();
	}

根据 TaskExecutionProperties我们可以配置如下参数:

spring:
  task:
    execution:
      thread-name-prefix: application-task- # 线程名称前缀
      shutdown:
        await-termination: true # 是否应等待已经提交的任务在关闭时完成
        await-termination-period: 1m # 等待剩余任务完成的最长时间
      pool:
        core-size: 10 # 核心线程数
        allow-core-thread-timeout: true # 核心线程在保持活动时间内没有任务到达时是否超时和终止的策略
        queue-capacity: 1000 # 队列容量。无限容量不会增加池,因此会忽略"max-size"属性
        max-size: 10 # 允许的最大线程数。如果任务正在填满队列,则池可以扩展到该大小以适应负载。如果队列没有边界,则忽略。
        keep-alive: 1m # 线程在终止前可能保持空闲的时间限制。

可以看到我们可以设置线程池的各种参数。但是Spring给我们提供的线程池按照声明式的就只有一个,实现方式参考其源代码:TaskExecutionAutoConfiguration

在我们实际的开发场景中我们经常会根据不同的业务场景定制不同的线程池,这样做的好处是防止这个业务场景下把线程奔溃了而不影响其它业务场景,而这样还能根据不同的业务场景对线程池进行调优,因此Spring默认提供的这一个线程池配置往往是不够的。为了定制不同的线程池我们之前经常会这样做:

@Configuration
@EnableAsync
public class ExecutorConfiguration {

    /**
     * 业务场景xxx线程池
     *
     * @param environment environment
     * @return Executor
     */
    @Bean
    public Executor xxxxExecutor(Environment environment) {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 定制线程池的各种东西
        // ...
        return executor;
    }
    
    /**
     * 业务场景xxx2线程池
     *
     * @param environment environment
     * @return Executor
     */
    @Bean
    public Executor xxxx2Executor(Environment environment) {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 定制线程池的各种东西
        // ...
        return executor;
    }
}

就如上面这样,我们有一种场景的线程池就定制一次。

由于我最近看别人的一些产品中看到过声明式创建对象(就是在配置文件中写好相关的配置,yml文件),然后把这个文件上传,他们就能给我们创建相关的实例,而不用去写代码。这不由的让我想起了我们这边是不是也可以这样,读取配置文件然后把配置文件的值设置到线程池对象中就可以了吗,这样还省去了我们去写这些高度类似的代码。相关实现代码:https://github.com/myszh/java-code-samples/tree/main/spring-async

  • ExecutorFactory:主要的核心类
  • AsyncConfiguration:主配置类

标签:异步,return,Spring,线程,executor,Async,public
来源: https://www.cnblogs.com/wdszh/p/16376994.html