springboot之异步方法

异步任务

Configuration配置:

需要@EnableAsync注解开启异步功能。
spring异步任务是通过ThreadPoolTaskExecutor实现的,实质是线程池,与线程池的配置一样,设置核心线程数量、最大线程数量、线程存活时间、等待队列的容量、任务拒绝策略;
spring执行异步任务就是在相应的线程池中使用线程来执行该异步方法。

@Configuration
@EnableAsync
public class TaskConfigure {
    @Bean(name = "taskA")
    public TaskExecutor taskA() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数量
        executor.setCorePoolSize(8);
        // 最大线程数量
        executor.setMaxPoolSize(20);
        // 线程存活时间
        executor.setKeepAliveSeconds(20);
        // 等待队列的容量
        executor.setQueueCapacity(200);
        // 超过最大线程数量+队列容量后任务的拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
    @Bean(name = "taskB")
    public TaskExecutor taskB() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(8);
        executor.setMaxPoolSize(20);
        executor.setKeepAliveSeconds(20);
        executor.setQueueCapacity(200);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

异步方法

在方法上使用@Async注解即成为异步方法,注解的value可填写ThreadPoolTaskExecutor线程池的bean名称指定使用该线程池,可以在配置中配置多个线程池,不同的任务可以使用不同的线程池

@Component
public class AfterRegisterTask {

    private static Logger logger = LoggerFactory.getLogger(AfterRegisterTask.class);

    @Async("taskA")
    public void sentEmail() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("senting email...");
    }

    @Async("taskB")
    public void sentTextMessage() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("senting text message...");
    }
}

测试代码,模拟注册之后发送邮件和短信

@SpringBootTest
class AfterRegisterTaskTest {
    private static Logger logger = LoggerFactory.getLogger(AfterRegisterTask.class);
    @Autowired
    private AfterRegisterTask task;

    @Test
    void resister() throws InterruptedException {
        logger.info("用户注册");
        logger.info("异步方法执行中...");
        task.sentEmail();
        task.sentTextMessage();
        logger.info("立即返回,不用等待异步任务的完成");
        // 留出时间给异步方法的线程,不然测试的main线程结束后,异步方法的日志不会打印
        Thread.sleep(1500);
    }
}

测试结果,方括号中显示的即使线程池名称+线程id,main线程执行了注册,在异步方法执行完成之前就返回了,不会阻塞,开启了异步的方法显示各自使用了配置的线程池里的线程

[           main] com.example.demo.AfterRegisterTask       : 用户注册
[           main] com.example.demo.AfterRegisterTask       : 异步方法执行中...
[           main] com.example.demo.AfterRegisterTask       : 立即返回,不用等待异步任务的完成
[        taskA-1] com.example.demo.AfterRegisterTask       : senting email...
[        taskB-1] com.example.demo.AfterRegisterTask       : senting text message...

ThreadPoolTaskExecutor

ThreadPoolTaskExecutor跟jdk里的ThreadPoolExecutor乍看上去很想,实质上ThreadPoolTaskExecutor就是封装了一个ThreadPoolExecutor实例来实现线程池的,ThreadPoolTaskExecutor的set方法实质都是设置封装的那个线程池对象。
ThreadPoolTaskExecutor源码:
其中的封装的线程池

    @Nullable
    private ThreadPoolExecutor threadPoolExecutor;

set方法设置线程池的属性

public void setCorePoolSize(int corePoolSize) {
        synchronized (this.poolSizeMonitor) {
            this.corePoolSize = corePoolSize;
            if (this.threadPoolExecutor != null) {
                this.threadPoolExecutor.setCorePoolSize(corePoolSize);
            }
        }
    }

你可能感兴趣的:(springboot之异步方法)