栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring框架 @Async异步注解组件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring框架 @Async异步注解组件

一、使用方式 1、启动类⾥⾯使⽤ @EnableAsync 注解开启功能,⾃动扫描 2、定义异步任务类并使⽤ @Component 标记组件被容器扫描 , 异步⽅法加上@Async
@Component
@Slf4j
public class SmsComponent {


    
    @Async
    public void send() {
       System.out.println("方法逻辑");
    }

}
二、失效情况

1、注解 @Async 的⽅法不是 public ⽅法 2、注解 @Async 的返回值只能为 void 或者 Future 3、注解 @Async ⽅法使⽤ static 修饰也会失效 4、spring ⽆法扫描到异步类,没加注解 @Async 或 @EnableAsync注解 5、调⽤⽅与被调⽅不能在同⼀个类        Spring 在扫描 bean 的时候会扫描⽅法上是否包含 @Async 注解,动态地⽣成⼀个⼦类(即proxy 代理类),当这个有注解的⽅法被调⽤的时候,实际上是由代理类来调⽤的,代理类在调⽤时增加异步作⽤如果这个有注解的⽅法是被同⼀个类中的其他⽅法调⽤的,那么该⽅法的调⽤并没有通过代理类,⽽是直接通过原来的那个 bean ,所以就失效了所以调⽤⽅与被调⽅不能在同⼀个类,主要是使⽤了动态代理,同⼀个类的时候直接调⽤,不是通过⽣成的动态代理类调⽤⼀般将要异步执⾏的⽅法单独抽取成⼀个类类中需要使⽤ @Autowired 或 @Resource 等注解⾃动注⼊,不能⾃⼰⼿动new 对象 6、在 Async ⽅法上标注 @Transactional 是没⽤的,但在 Async ⽅法调⽤的⽅法上标注@Transactional 是有效的 三、注意事项 @Async 注解没指定线程池的话,即未设置TaskExecutor时默认使⽤Spring 创建ThreadPoolTaskExecutor, 默认 8 个核⼼线程数占⽤满了之后 , 新的调⽤就会进⼊队列 , 最 ⼤值是Integer.MAX_VALUE,极容易出现 OOM ,或者消息丢失。   附加: ThreadPoolTaskExecutor 和 ThreadPoolExecutor区别?                  1、ThreadPoolExecutor ,这个类是 JDK 中的线程池类,继承⾃ Executor,⾥⾯有⼀个                         execute() ⽅法,⽤来执⾏线程,线程 池主要提供⼀个线程队列,队列中保存着所有等                    待状态的线 程,避免了创建与销毁的额外开销。              2、ThreadPoolTaskExecutor ,是 spring 包下的,是 Spring 为我 们提供的线程池类 Spring                    异步线程池的接⼝类是 TaskExecutor ,本质还是 java.util.concurrent.Executor 源代码位置: TaskExecutionProperties
	public static class Pool {

		
		private int queueCapacity = Integer.MAX_VALUE;

		
		private int coreSize = 8;

		
		private int maxSize = Integer.MAX_VALUE;

		
		private boolean allowCoreThreadTimeout = true;

TaskExecutionAutoConfiguration

四、解决方案 spring 会先搜索 TaskExecutor 类型的 bean 或者名字为 taskExecutor的 Executor 类型的 bean, 所以我们最好来⾃定义⼀个线程池,加⼊ Spring IOC 容器⾥⾯,即可覆盖
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {


    @Bean("threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        //线程池创建的核⼼线程数,线程池维护线程的最少数ᰁ,即使没有任务需要执⾏,也会⼀直存活
        //如果设置allowCoreThreadTimeout=true(默认false)时,核⼼线程会超时关闭

        threadPoolTaskExecutor.setCorePoolSize(4);
        //最⼤线程池数ᰁ,当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
        //当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务⽽抛出异常
        threadPoolTaskExecutor.setMaxPoolSize(8);
        //缓存队列(阻塞队列)当核⼼线程数达到最⼤时,新任务会放在队列中排队等待执⾏

        threadPoolTaskExecutor.setQueueCapacity(124);

        //当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数ᰁ=corePoolSize
        //允许线程空闲时间60秒,当maxPoolSize的线程在空闲时间到达的时候销毁
        //如果allowCoreThreadTimeout=true,则会直到线程数ᰁ=0

        threadPoolTaskExecutor.setKeepAliveSeconds(30);

        //spring 提供的 ThreadPoolTaskExecutor 线程池,是有setThreadNamePrefix() ⽅法的。
        //jdk 提供的ThreadPoolExecutor 线程池是没有setThreadNamePrefix() ⽅法的

        threadPoolTaskExecutor.setThreadNamePrefix("xcw-Async前缀:");

        threadPoolTaskExecutor.setWaitForTasksToCompleteonShutdown(true);

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CallerRunsPolicy():交由调⽤⽅线程运⾏,⽐如main 线程;如果添加到线程池失败,那么主线程会⾃⼰去执⾏该任务,不会等待线程池中的线程去执⾏
//AbortPolicy():该策略是线程池的默认策略,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常。
//DiscardPolicy():如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常
//DiscardOldestPolicy():丢弃队列中最⽼的任务,队列满了,会将最早进⼊队列的任务删掉腾出空间,再尝试加⼊队列


        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }


}
// 使⽤实战, 启动类可以不加 @EnableAsync ,改上⾯加 @Async("threadPoolTaskExecutor")

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/581847.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号