0
点赞
收藏
分享

微信扫一扫

【@Async注解实现异步调用】

阎小妍 2022-02-23 阅读 80

前言

先说一下我们为什么会使用这个注解,当我们在执行逻辑的时候,有一个不是很关键的业务,就是保存日志,因为保存日志它不是客户需求,又为了减小系统与用户之间的延迟,那我们就可以重新启动一个线程去执行保存日志,主线程继续执行业务即可。

同步

异步

配置

业务

/**
 * @Classname AsyncService
 * @Description 异步线程
 * @Date 2022/2/23 16:32
 * @Author zhaoxiaodong
 */
@Slf4j
@Async
@Component
public class AsyncService {

    public void test01(){
        Thread thread = Thread.currentThread();
        log.info("线程--->{}",thread.getName());
    }
}

配置

package com.example.zxdtest.config;

import com.alibaba.ttl.threadpool.TtlExecutors;
import com.example.zxdtest.ZxdtestApplication;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.*;

/**
 * @Classname AsyncConfig
 * @Description 异步线程池的配置
 * @Date 2022/2/23 16:33
 * @Author zhaoxiaodong
 */
@Slf4j
@EnableAsync
@Configuration
public class AsyncConfig {
    private final TaskExecutionProperties taskExecutionProperties;

    @Autowired
    public AsyncConfig(TaskExecutionProperties taskExecutionProperties){
        this.taskExecutionProperties = taskExecutionProperties;
    }

    @Bean()
    public Executor taskExecutor(){
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(taskExecutionProperties.getPool().getCoreSize());
        taskExecutor.setMaxPoolSize(taskExecutionProperties.getPool().getMaxSize());
        taskExecutor.setQueueCapacity(taskExecutionProperties.getPool().getQueueCapacity());
        taskExecutor.setKeepAliveSeconds((int) taskExecutionProperties.getPool().getKeepAlive().getSeconds());
        taskExecutor.setThreadNamePrefix(taskExecutionProperties.getThreadNamePrefix());
        taskExecutor.setWaitForTasksToCompleteOnShutdown(taskExecutionProperties.getShutdown().isAwaitTermination());
        taskExecutor.setAwaitTerminationSeconds((int) taskExecutionProperties.getShutdown().getAwaitTerminationPeriod().getSeconds());
        taskExecutor.setRejectedExecutionHandler(new Hc360CrmRejectedExecutionHandler());
        taskExecutor.initialize();
        // return taskExecutor;
        return TtlExecutors.getTtlExecutor(taskExecutor);
    }
    private static class Hc360CrmRejectedExecutionHandler implements RejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            String msg = String.format("Threadpool is exhausted, Reject Task Name:%s, Pool Size:%d (active:%d, core:%d, max:%d, largest:%d), Task:%d (completed:%d), Executor status: (isShutdown:%s, isTerminated:%s, isTerminating:%s)",
                    r.toString(), executor.getPoolSize(), executor.getActiveCount(), executor.getCorePoolSize(), executor.getMaximumPoolSize(), executor.getLargestPoolSize(),
                    executor.getTaskCount(), executor.getCompletedTaskCount(), executor.isShutdown(), executor.isTerminated(), executor.isTerminating());
            log.warn(msg);
            try {
                executor.getQueue().offer(r, 60, TimeUnit.SECONDS);
            } catch (InterruptedException ignored) {
            }
        }
    }
}

YML的配置

spring:
  task:
    execution:
      thread-name-prefix: ZXD-ESPROJECT-ThreadPool-
      pool:
        core-size: 10
        max-size: 50
        queue-capacity: 50
        keep-alive: PT30S
        allow-core-thread-timeout: true
      shutdown:
        await-termination: true
        await-termination-period: PT2M

单元测试


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class ZxdtestApplicationTests {

    @Autowired
    private AsyncService asyncService;
    @Autowired
    private ZxdTestService zxdTestService;

    @Test
    void contextLoads() {
       asyncService.selectAsyncDo();
    }
    @Test
    void test1(){
        zxdTestService.testOne();;
    }

}
```java
2022-02-23 18:24:41.244 - INFO 85300 --- [   HC360-CRM-ThreadPool-1] com.hc360.crm.service.AsyncService       : 线程--->ZXD-ESPROJECT-ThreadPool-

总结

我们用@Async最好要重写线程池, Spring应用默认的线程池,指在@Async注解在使用时,不指定线程池的名称。查看源码,@Async的默认线程池为SimpleAsyncTaskExecutor。每次都会重新创建一个线程。

举报

相关推荐

0 条评论