首页 > 其他分享 >Spring中@Async注解使用及配置

Spring中@Async注解使用及配置

时间:2022-12-05 13:57:04浏览次数:58  
标签:异步 Spring public 线程 Async 注解 class

Spring中@Async注解使用及配置

参考文章:https://blog.csdn.net/weixin_42272869/article/details/123082657

一、@Async注解的使用

在使用spring框架中,可以非常简单方便的实现一个异步执行方法,具体只需要在启动类添加@EnableAsync注解开启支持异步,然后在需要进行异步处理的方法上使用@Async注解即可进行异步执行。

注意:想要异步执行,不能在一个类中直接调用本类中被@Async注解标记的方法,本类中直接调用会同步执行,不会进行异步执行

主启动类

@EnableAsync//开启异步支持,也可以标记在被@Configuration注解标注的类上,效果一致
@SpringBootApplication
public class ApplicationTest{
  ....
}

使用实例:需要交给spring容器管理bean

@Component
public class MyAsyncService {

    @Async//直接使用异步注解即可,默认使用的线程池就是自定义实现的线程池
    public void testAsync(){
        System.out.println("==== 我执行了 ====");
        System.out.println("MyAsyncService.testAsync() = " + Thread.currentThread().getName());
    }

}

测试执行:

/* 使用SpringBoot执行测试 */
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {

    @Resource
    MyAsyncService myAsyncService;
  
    @Test
    void testTread(){
        myAsyncService.testAsync();
        System.out.println("结束.... " );
    }
}

测试结果:
image

二、@Async注解线程池的配置及使用

1、@Async默认线程池修改

对于修改@Async使用的默认线程池,我们可以使用实现AsyncConfigurer接口,并重写getAsyncExecutor()方法,为其提供我们自己定义的线程池即可

具体示例:

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 描述:线程池配置类,修改@Async注解默认使用的线程池
 *
 * @author SXT
 * @version 1.0
 * @date 2022/11/22
 */
//开启自动启用异步注解,与配置类放在一起,方便管理 
@EnableAsync
@Configuration
@Slf4j
public class AsyncTaskPoolConfig implements AsyncConfigurer {

    /**
     * 用于@Async注解获取默认线程连接池
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        //此类由Spring提供,org.springframework.scheduling.concurrent包下,是线程池的封装类
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //线程池中线程的名字前缀
        taskExecutor.setThreadNamePrefix("taskThreadPool-async-");
        //线程池核心线程数量
        taskExecutor.setCorePoolSize(5);
        //线程池最大线程数量
        taskExecutor.setMaxPoolSize(10);
        //线程池空闲线程存活时间,单位秒
        taskExecutor.setKeepAliveSeconds(100);
        //线程池拒绝策略
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        //线程池任务队容量,如果不设置则默认 Integer.MAX_VALUE,
        // 队列默认使用LinkedBlockingQueue 若queueCapacity的值 <= 0,则使用SynchronousQueue
        taskExecutor.setQueueCapacity(1000);

        //线程池中核心线程是否允许超时,默认为false
        taskExecutor.setAllowCoreThreadTimeOut(true);

        //线程池中的超时处理时间,单位秒,有一个对应方法为毫秒,默认为不超时
        taskExecutor.setAwaitTerminationSeconds(60);

        //初始化线程池,不可以少,否者会抛出 线程池没有初始化
        taskExecutor.initialize();
        return taskExecutor;
    }

    /**
     * 线程未处理异常的统一处理机制,即线程池异常处理器,简单示例
     * @return
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        // 异常处理器函数接口类
        return new AsyncUncaughtExceptionHandler() {
            @Override
            public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
                log.error("============ " + throwable.getMessage() + " ===========", throwable);
                log.error("============ " + method.getName() + " ===========", objects);
            }
        };
    }
}

实现AsyncConfigurer类中的getAsyncExecutor()方法后,在使用@Async注解进行异步执行时,默认使用的线程池就是实现提供的线程池,具体使用示例如下:

/**
 * 描述:异步方法调用
 *
 * @author SXT
 * @version 1.0
 * @date 2022/11/23
 */
@Component
public class MyAsyncService {

    @Async//直接使用异步注解即可,默认使用的线程池就是自定义实现的线程池
    public void testAsync(){
        System.out.println("==== 我执行了 ====");
        System.out.println("MyAsyncService.testAsync() = " + Thread.currentThread().getName());
    }

}

/* 使用SpringBoot执行测试 */
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {

    @Resource
    MyAsyncService myAsyncService;
  
    @Test
    void testTread(){
        myAsyncService.testAsync();
        System.out.println("结束.... " );
    }
}

测试执行结果如下:如实使用实现提供的线程池

image

2、自定义线程池(@Async指定使用自定义线程池)

无论是修改@Async默认提供的线程池还是不修改,都可以对某些使用@Async标注的异步执行方法为其指定使用具体的某一个线程池,若想要使用指定的线程池需要明确的为@Async注解指定使用的线程池名称(自定义的线程池需要交给Spring管理),也就是bean的名称

自定义线程池示例:可以看到与修改@Async默认线程池中提供线程池的内容一样,线程池具体的配置可以根据需求进行设置

@Configuration
public class CommentConfig {

  /**
     * 自定义异步线程池,bean的名字如果不显示的指定,则默认使用方法的名称作为bean的名称
     * @return
     */
    @Bean("asyncTaskPool")
    public Executor asyncTaskPool(){
        //此类由Spring提供,org.springframework.scheduling.concurrent包下,是线程池的封装类
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //线程池中线程的名字前缀
        executor.setThreadNamePrefix("asyncTaskPool-task-");
        //线程池核心线程数量
        executor.setCorePoolSize(5);
        //线程池最大线程数量
        executor.setMaxPoolSize(10);
        //线程池空闲线程存活时间,单位秒
        executor.setKeepAliveSeconds(100);
        //线程池拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //线程池任务队容量,如果不设置则默认 Integer.MAX_VALUE,
        // 队列默认使用LinkedBlockingQueue 若queueCapacity的值 <= 0,则使用SynchronousQueue
        executor.setQueueCapacity(1000);

        //线程池中核心线程是否允许超时,默认为false
        executor.setAllowCoreThreadTimeOut(true);

        //线程池中的超时处理时间,单位秒,有一个对应方法为毫秒,默认为不超时
        executor.setAwaitTerminationSeconds(60);

        //初始化线程池,不可以少,否者会抛出 线程池没有初始化
        executor.initialize();
        return executor;
    }

}

使用自定义线程池示例:

/**
 * 描述:异步方法调用
 *
 * @author SXT
 * @version 1.0
 * @date 2022/11/23
 */
@Component
public class MyAsyncService {
		
  	//指定使用线程池的bean的名称,不指定的话使用的是默认提供的线程池
    //asyncTaskPool就是被Spring管理的线程池实例的对象名称
    @Async("asyncTaskPool")
    public void testAsync2(){
        System.out.println("==== 我执行了 ====");
        System.out.println("MyAsyncService.testAsync2() = " + Thread.currentThread().getName());
    }

}


/* 使用SpringBoot执行测试 */
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {

    @Resource
    MyAsyncService myAsyncService;
  
    @Test
    void testTread2(){
        myAsyncService.testAsync2();
        System.out.println("结束.... " );
    }
}

测试结果如下:

image

拓展:

若想要根据配置文件进行动态的配置自定义线程池,则可以使用如下方式

配置文件properties文件或yml文件

#这里使用properties文件进行配置,yml文件同样的方式,只是格式不同
#也可以将驼峰命名改成core-size ,keep-alive-seconds,对应的实体类依旧是驼峰命名
asyncTask.pool.coreSize=5
asyncTask.pool.maxPoolSize=10
asyncTask.pool.keepAliveSeconds=60
asyncTask.pool.queueCapacity=1000
asyncTask.pool.timeOutSeconds=60

定义获取配置文件对应配置的类

/**
 * 描述:线程池配置文件实体类
 *
 * @author SXT
 * @version 1.0
 * @date 2022/11/23
 */
//使用@ConfigurationProperties注解,其类必须交给Spring管理
@ConfigurationProperties(prefix = "async-task.pool")
@Component
@ToString
@Data
public class ThreadConfig {

    private int coreSize;

    private int maxPoolSize;

    private long keepAliveSeconds;

    private int queueCapacity;

    private long timeOutSeconds;

}

@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {

    @Autowired
    ThreadConfig threadConfig;

    @Test
    void testProperties1(){
        System.out.println("threadConfig = " + threadConfig);

    }
}

测试结果:
image

提示:配置的key不要写错,不然获取不到值

三、@Async注解的原理

待完善

标签:异步,Spring,public,线程,Async,注解,class
From: https://www.cnblogs.com/qiushuiyu-108/p/16940205.html

相关文章

  • @EnableEurekaServer注解不可用
    1.可能是springBoot版本和spingCloud版本不匹配parentpom做了如下修改<!--基于springboot开发--><parent><groupId>org.springframework.boot</groupId><artifactId......
  • extjs4,spring mvc3上传文件
    本文讲解下extjs4结合springmvc3的注解完成上传文件的例子。1页面文件  <!--ExtJSFiles--><linkrel="stylesheet"type="text/css......
  • Spring Boot注入静态变量
    SpringBoot注入静态变量@value或者@Autowired不能直接注入值给静态属性,spring不允许/不支持把值注入到静态变量中;spring支持set方法注入,我们可以利用非静态setter方法......
  • Spring
    组成SpringCore:核心容器,BeanFactory提供了组件生命周期的管理,组件的创建、装配,销毁等功能。SpringContext:实现了ApplicationContext接口,Spring的上下文,拓展了核心容......
  • 源码解析:Dubbo3 的 Spring 适配原理与初始化流程
    Dubbo国内影响力最大的开源框架之一,非常适合构建大规模微服务集群的,提供开发框架、高性能通信、丰富服务治理等能力。同时Dubbo无缝支持Spring、SpringBoot模式的开......
  • Spring Cloud Vault Config
    9.自定义要公开为属性源的机密后端SpringCloudVault使用基于属性的配置来创建键值和发现的秘密后端。​​PropertySource​​发现的后端提供bean来描述使用机密后端的......
  • Spring中获取request的几种方法,及其线程安全性分析
    前言本文将介绍在SpringMVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性。目录概述如何测试线程安全性方法1:Controller中加参数方法2:自动注入方法3......
  • 如何使用 Spring Cloud Zookeeper 进行服务发现和分布式配置
    该项目通过以下方式为SpringBoot应用程序提供Zookeeper集成自动配置并绑定到Spring环境和其他Spring编程模型习语。通过一些注释,您可以快速启用和配置常见模式......
  • springmvc注册fastJson报错
    原因:依赖版本问题这是我原本引入的依赖,版本是1.2.24<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId......
  • spring-boot-@Valid和@Validated详解
    ----------------------------------------------------------------------------------------在实际的项目开发中,经常会遇到对参数进行校验的场景,最常见的就是后端需要对......