java - @Async 具体使用

1.开启  @Async 异步能力

添加注解 @EnableAsync ,可以放在启动类上,也可以在任意配置类上,因为我是需要配置自定义线程池,因此放在配置类上

复制代码
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.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

//开启异步线程能力
@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(10);
        // 最大线程数
        executor.setMaxPoolSize(20);
        // 队列大小
        executor.setQueueCapacity(1000);
        // 线程最大空闲时间
        executor.setKeepAliveSeconds(300);
        // 指定用于新创建的线程名称的前缀。
        executor.setThreadNamePrefix("async-cenxi-Executor-");
        // 拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 这一步千万不能忘了,否则报错: java.lang.IllegalStateException: ThreadPoolTaskExecutor not initialized
        executor.initialize();
        return executor;
    }
}
复制代码

2.使用

如果在同一个类中使用方法,需要先获取该方法的类的代理类,不能直接待用,如果直接调用,效果为同步操作

这里封装个获取代理类的工具类

复制代码
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringApplicationUtil implements ApplicationContextAware {
    private static ApplicationContext ctx = null;

    public SpringApplicationUtil() {
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (ctx == null) {
            ctx = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return ctx;
    }

    public static <T> T getBean(Class<T> requiredType) {
        return ctx.getBean(requiredType);
    }

    public static <T> T getBean(String name, Class<T> requiredType) {
        return ctx.getBean(name, requiredType);
    }
}
View Code
复制代码

使用写法如下

SpringApplicationUtil.getBean(【方法的类名】.class).【需要调用的异步方法】();

例子

 

 

 不在同一个类中调用方法,直接在方法上加 后 ,在需要调用的地方注入类接口

 

3.有个bug,子线程无法获取主线程的参数或者http请求参数,怎么办?下面可以解决

解决

在调用子线程方法之前,设置请求上下文为继承配置即可,加入下面这句指令即可。

每个主线程只需要设置一次即可,因此应该在最开头的地方设置,因此设置位置看项目具体需要

RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);

4.有个解决不了的bug

当主线程完全结束后,HttpServletRequest 获取不到数据,为null ,因此会发现有时候能获取到值,有时候为nul ,这就是谁先谁后的原因导致的

因此,对于传参,应该获取到静态值后传入异步函数中,如果仍不满足要求,那只能弃用该方式了

 

posted @   岑惜  阅读(1265)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示