快捷搜索: 王者荣耀 脱发

SpringBoot 异步任务-使用@Async注解

常见的高并发方案

    异步,削峰填谷 缓存,缓存相对稳定高频热点数据 并行,缩短业务响应时间 优化你的业务代码 限流和降级,保护你的核心服务在高并发下能正常工作

异步场景

关联业务的执行结果对主线程的返回结果没有直接影响或无影响。此时,能让主线程更顺畅的执行,并给客户带来好的客户体验,可以将该关联业务做异步处理或类似的处理(如:消息队列)

@Async

该工具提供方便快捷的异步化执行业务的能力,只需要添加一个注解@Async既可以使你的业务异步执行,这里的异步执行,指的是新开一个线程业务;该注解可以使用到类上,也可以使用在方法上。

    @EnableAsync启用异步化能力注解,推荐该注解配置在springboot的Config类或者启动类上 @Async开启异步化模式注解 AsyncConfigurer全局配置接口,用于配置自定义异步线程池和异步线程执行异常捕获器 AsyncUncaughtExceptionHandler异步化运行时全局异常捕获接口 AsyncExecutor异步化执行线程池,自定义异步执行线程池

注意事项

    SpringBootApplication启动类添加@EnableAsync注解; @Async使用 类或者方法中使用@Async注解,类上标有该注解表示类中方法都是异步方法,方法上标有该注解表示方法是异步方法 @Async(“threadPool”),threadPool为自定义线程池,这样可以保证主线程中调用多个异步任务时能更高效的执行 在定义异步方法的同一个类中,调用带有@Async注解方法,该方法则无法异步执行 注解的方法必须是public方法,不能是static @Async注解的实现和@Transactional一样,都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的,所以要经过Spring容器管理,否则调用方法的是对象本身而不是代理对象

无参数异步化接口示例

@Async
public void executeTask(){
    //业务操作
}

带参数异步化接口

@Async
public Future<T> task2(){
    //业务操作,T代指实体类/Object
    
    //返回操作结果
    return new AsyncResult<>(new User("zhangsan", 22));
}

自定义线程池

@Configuration
@EnableAsync
public class ExecutorConfig {
    private int corePoolSize = 10;
    private int maxPoolSize = 50;
    private int queueCapacity = 10;
 
    @Bean
    public Executor testAsync() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix("MgmtExecutor-");
 
        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

使用

@Async("testAsync") // 自定义执行线程池

测试

100次调用,循环加一百减一百,并对计算时间随机处理,a最终结果应为6

controller

@PostMapping("/test")
    public CommonResult test(@RequestBody ThirdPayParam param) {
        for (int i = 0; i < 100; i++) {
            testUtil.executeTask(i%2 == 0 ?100 : -100);
        }
        return CommonResult.success(null);
    }

TestUtil

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class TestUtil {

    public static int a = 6;
    @Async
    public void executeTask(int b){
        System.out.println(a);
        try {
            Thread.sleep((long) ((Math.random() + 1) * 1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        a = a + b;
        System.out.println("最终结果" + a);
    }
}

嗯,后续再补充

经验分享 程序员 微信小程序 职场和发展