SpringBoot 自定义线程池处理异步任务

1. 为什么要异步

当我们开发中涉及短信发送,邮件发送等耗时请求时可以通过执行异步操作,从而加快请求响应,使用户体验更友好

2. 具体操作

创建springboot项目引入weblombok
完整的pom.xml如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>thread-pool-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>thread-pool-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.1 配置application.yml

#线程池配置参数
task:
  pool:
    corePoolSize: 5 #设置核心线程数
    maxPoolSize: 20  #设置最大线程数
    keepAliveSeconds: 300 #设置线程活跃时间(秒)
    queueCapacity: 50 #设置队列容量
    threadNamePrefix: # 线程名称前缀

2.2 编写线程池配置类

@ConfigurationProperties(prefix = "task.pool")
@Data
public class TaskThreadPoolConfig {
    private int corePoolSize;           // 核心线程数(默认线程数)
    private int maxPoolSize;              // 最大线程数
    private int keepAliveTime;         // 允许线程空闲时间(单位:默认为秒)
    private int queueCapacity;        // 缓冲队列数
    private String threadNamePrefix; // 线程池名前缀
}

2.3 在启动类上开启线程异步支持

@SpringBootApplication
@EnableAsync        //开启线程异步支持
@EnableConfigurationProperties({TaskThreadPoolConfig.class}) // 引入自定义线程池配置
public class ThreadPoolDemoApplication {

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

}

2.4 创建自定义线程池

@Configuration
public class MyThreadPoolTaskExecutor {
    @Autowired
    private TaskThreadPoolConfig config;

    /**
     * 默认异步线程池
     *
     * @return
     */
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setThreadNamePrefix(config.getThreadNamePrefix());
        pool.setCorePoolSize(config.getCorePoolSize());
        pool.setMaxPoolSize(config.getMaxPoolSize());
        pool.setKeepAliveSeconds(config.getKeepAliveTime());
        pool.setQueueCapacity(config.getQueueCapacity());
        // 直接在execute方法的调用线程中运行
        pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        pool.setWaitForTasksToCompleteOnShutdown(true);
        // 初始化
        pool.initialize();
        return pool;
    }

}

2.5 编写测试ServiceController

@Service
public class TaskService {
    @Async
    public void doTaskA() throws InterruptedException {
        System.out.println("TaskA thread name->" + Thread.currentThread().getName() + "start");
        Long startTime = System.currentTimeMillis();
        TimeUnit.SECONDS.sleep(3);
        Long endTime = System.currentTimeMillis();
        System.out.println("TaskA thread name->" + Thread.currentThread().getName() + "finish");
        System.out.println("TaskA 耗时:" + (endTime - startTime));
    }

    @Async
    public void doTaskB() throws InterruptedException {
        System.out.println("TaskB thread name->" + Thread.currentThread().getName() + "start");
        Long startTime = System.currentTimeMillis();
        TimeUnit.SECONDS.sleep(3);
        Long endTime = System.currentTimeMillis();
        System.out.println("TaskB thread name->" + Thread.currentThread().getName() + "finish");
        System.out.println("TaskB耗时:" + (endTime - startTime));
    }
}

@RestController
public class HelloController {
    @Autowired
    private TaskService taskService;

    @GetMapping("/async")
    public String testAsync() throws Exception {
        System.out.println("主线程 name -->" + Thread.currentThread().getName() + "start");
        Long startTime = System.currentTimeMillis();
        taskService.doTaskA();
        taskService.doTaskB();
        Long endTime = System.currentTimeMillis();
        System.out.println("主线程 name -->" + Thread.currentThread().getName() + "finish");
        System.out.println("主线程" + Thread.currentThread().getName() + "耗时:" + (endTime - startTime));
        return "Hello World";
    }
}

测试结果

代码

微云下载

参考

SpringBoot 自定义线程池
SpringBoot自定义线程池处理异步任务

猜你喜欢

转载自www.cnblogs.com/ifme/p/12800092.html