SpringBoot项目使用@Async自定义线程池执行方法

实际开发过程中,经常遇到业务中需要异步来执行一些业务,SpringBoot给我们提供了简便执行异步业务的注解@Async 如何使用该注解:

  • 步骤:

导入依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.14</version>
        <relativePath/>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.11</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>

启动类:

启动类需要添加 @EnableAsync注解 ,以可以使用@Async注解

package com.sun.mycode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class MyCodeApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyCodeApplication.class, args);
    }

}

Service使用该注解执行

/**
 * 异步执行的服务类
 */
public interface AsyncExecuteService {

    public <T>void doExecuteDefaultAsync(T t);

    
}

impl:


@Slf4j
@Service
public class AsyncExecuteServiceImpl implements AsyncExecuteService {
    @Override
    @Async
    public <T> void doExecuteDefaultAsync(T t) {
        try {
            //避免执行太快看不到效果
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("当前线程Id{} threadName:{}",Thread.currentThread().getId(),Thread.currentThread().getName());
        //todo do t Service 执行业务方法
        String s = JSONUtil.toJsonStr(t);
        System.out.println(s);
    }

}

 测试类书写:

@SpringBootTest
class MyCodeApplicationTests {
    @Resource
    private AsyncExecuteService asyncExecuteService;

   
    @Test
    public void test2() {


        for (int i = 0; i < 100; i++) {

            asyncExecuteService.doExecuteDefaultAsync(IdUtil.fastSimpleUUID());
        }
        while (true) {

        }
    }

}

 测试结果:

 可见会开启不同线程来执行具体方法:

此处需要注意:如果没有在@Async注解中指定线程池,就会使用默认的线程池SimpleAsyncTaskExecutor。该线程池默认来一个任务创建一个线程,在压测情况下,会有大量请求,这时就会不断创建大量线程,极有可能出现OOM的问题。

在实际开发中我们需要自定义线程池来进行控制创建的线程:

自定义线程池配置:

@Configuration
@ConfigurationProperties(prefix = "async.executor.thread")
@Data
public class ExecutorConfig implements AsyncConfigurer {

    private Integer corePoolSize;

    private Integer maxPoolSize;

    private Integer queueCapacity;

    private String prefix;

    @Override
    @Bean("asyncExecutor")
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        //配置线程池中线程的名称前缀
        executor.setThreadNamePrefix(prefix);
        //策略ThreadPoolExecutor.AbortPolicy():丢弃任务并抛出RejectedExecutionException异常。 默认策略
        //ThreadPoolExecutor.DiscardPolicy():也是丢弃任务,但是不抛出异常。
        //ThreadPoolExecutor.DiscardOldestPolicy():丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
        //ThreadPoolExecutor.CallerRunsPolicy():由调用线程处理该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}

application.yml配置文件:

async:
  executor:
    thread:
      corePoolSize: 5
      maxPoolSize: 5
      queueCapacity: 999
      prefix: async

 service书写:

public interface AsyncExecuteService {

   

    public <T>void doExecuteAsync(T t);
}

impl:

@Slf4j
@Service
public class AsyncExecuteServiceImpl implements AsyncExecuteService {
  

    @Override
    @Async("asyncExecutor")
    public <T> void doExecuteAsync(T t) {
        try {
            //避免执行太快看不到效果
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("当前线程Id{} threadName:{}",Thread.currentThread().getId(),Thread.currentThread().getName());
        //todo do t Service 执行业务方法
        String s = JSONUtil.toJsonStr(t);
        System.out.println(s);
    }
}

测试类书写:

@SpringBootTest
class MyCodeApplicationTests {
    @Resource
    private AsyncExecuteService asyncExecuteService;

    @Test
    public void test1() {


        for (int i = 0; i < 50; i++) {

            asyncExecuteService.doExecuteAsync(IdUtil.fastSimpleUUID());
        }
        while (true) {

        }
    }

   

}

测试结果:

 可见是由我们自定义的线程池创建的线程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值