跳至主要內容

springboot线程池

chanchaw大约 2 分钟javaspring

APP开启多线程

在 ShowApplication.java 启动类头上添加下面两个注解,注意类 EmailThreadPoolConfig 指定了读取项目配置文件参数并创建 bean 对象到 app 中

@EnableAsync
@EnableConfigurationProperties({EmailThreadPoolConfig.class} ) // 开启配置属性支持

线程池配置文件

threadpool:
  email:
    corePoolSize: 20
    maxPoolSize: 40
    keepAliveSeconds: 300
    queueCapacity: 50

配置文件类

package com.xdf.showa.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author chanchaw
 * @create 2023-06-22 16:37
 */
@ConfigurationProperties(prefix = "threadpool.email")
public class EmailThreadPoolConfig {
    private int corePoolSize;
    private int maxPoolSize;
    private int keepAliveSeconds;
    private int queueCapacity;

    public int getCorePoolSize() {
        return corePoolSize;
    }

    public void setCorePoolSize(int corePoolSize) {
        this.corePoolSize = corePoolSize;
    }

    public int getMaxPoolSize() {
        return maxPoolSize;
    }

    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }

    public int getKeepAliveSeconds() {
        return keepAliveSeconds;
    }

    public void setKeepAliveSeconds(int keepAliveSeconds) {
        this.keepAliveSeconds = keepAliveSeconds;
    }

    public int getQueueCapacity() {
        return queueCapacity;
    }

    public void setQueueCapacity(int queueCapacity) {
        this.queueCapacity = queueCapacity;
    }

    @Override
    public String toString() {
        return "EmailThreadPoolConfig{" +
                "corePoolSize=" + corePoolSize +
                ", maxPoolSize=" + maxPoolSize +
                ", keepAliveSeconds=" + keepAliveSeconds +
                ", queueCapacity=" + queueCapacity +
                '}';
    }
}

线程池类

package com.xdf.showa.config;

import org.springframework.beans.factory.annotation.Autowired;
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.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author chanchaw
 * @create 2023-06-22 16:39
 */
@Configuration
@EnableAsync
public class EmailThreadPool {
    @Autowired
    private EmailThreadPoolConfig config;

    @Bean
    public Executor ccEmailThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程池大小
        executor.setCorePoolSize(config.getCorePoolSize());
        //最大线程数
        executor.setMaxPoolSize(config.getMaxPoolSize());
        //队列容量
        executor.setQueueCapacity(config.getQueueCapacity());
        //活跃时间
        executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
        //线程名字前缀
        executor.setThreadNamePrefix("ccEmailThread-");

        // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
        // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

用于测试的业务功能

package com.xdf.showa.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @author chanchaw
 * @create 2023-06-22 16:42
 */
@Slf4j
@Component
public class AsyncTask {
    @Async("ccEmailThreadPool")  //ccEmailThreadPool即配置线程池的方法名,此处如果不写自定义线程池的方法名,会使用默认的线程池
    public void doTask1(int i) throws InterruptedException{
        log.info("Task"+i+" started.");
    }
}

测试

在任意 bean 的类中自动注入业务逻辑类 AsyncTask 并通过循环调用多个任务测试是否使用了多线程,注意看日志文件。软件中发送邮件会比较耗时,要采用线程池的方式发送邮件

@Autowired
private AsyncTask asyncTask;

@PostConstruct
public void testEmailThreadPool() throws InterruptedException {
    log.info("开始线程池任务");
    for(int i=0;i<20;i++){
        asyncTask.doTask1(i);
    }
    log.info("线程池任务结束");
}