其他分享
首页 > 其他分享> > Springboot线程池ThreadPoolTaskExecutor与@Async详解使用

Springboot线程池ThreadPoolTaskExecutor与@Async详解使用

作者:互联网

Springboot整合ThreadPoolTaskExecutor线程池

在springboot当中,根据官方文档官方文档的说明,如果没有配置线程池的话,springboot会自动配置一个ThreadPoolTaskExecutor线程池到bean当中,我们只需要按照它的方式调用就可以了。

使用springboot默认的线程池

demo测试,不配置线程池,采用springboot默认的线程池

测试方式一:

首先在application启动类添加@EnableAsync

@SpringBootApplication
@EnableAsync
public class ThreadpoolApplication {
    public static void main(String[] args) {
        SpringApplication.run(ThreadpoolApplication.class, args);
    }
}

第二步,在需要异步执行的方法上加上@Async注解

@Service
public class AsyncTest {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Async
    public void hello(String name){
    	//这里使用logger 方便查看执行的线程是什么
        logger.info("异步线程启动 started."+name);  
    }
}

第三步,测试类进行测试验证

  @Autowired
    AsyncTest asyncTest;
    @Test
    void contextLoads() throws InterruptedException {
        asyncTest.hello("afsasfasf");
        //一定要休眠 不然主线程关闭了,子线程还没有启动
        Thread.sleep(1000);
    }

日志结果:

INFO 2276 — [ main] c.h.s.t.t.ThreadpoolApplicationTests : Started ThreadpoolApplicationTests in 3.003 seconds (JVM running for 5.342) INFO 2276 — [ task-1] c.h.s.threadpool.threadpool.AsyncTest : 异步线程启动 started.afsasfasf

看到新开了一个task-1的线程执行任务。验证成功。

测试方式二:

直接调用ThreadPoolTaskExecutor,修改下测试类,直接注入ThreadPoolTaskExecutor

@Autowired
    AsyncTest asyncTest;
    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Test
    void contextLoads() throws InterruptedException {
        asyncTest.hello("async注解创建");
        threadPoolTaskExecutor.submit(new Thread(()->{
            logger.info("threadPoolTaskExecutor 创建线程");
        }));
        //一定要休眠 不然主线程关闭了,子线程还没有启动
        Thread.sleep(1000);
    }

打印日志:

INFO 12360 — [ task-2] c.h.s.t.t.ThreadpoolApplicationTests : threadPoolTaskExecutor 创建线程 INFO 12360 — [ task-1] c.h.s.threadpool.threadpool.AsyncTest : 异步线程启动 started.async注解创建

备注1:如果只使用ThreadPoolTaskExecutor,是可以不用在Application启动类上面加上@EnableAsync注解的。

备注2:多次测试发现ThreadPoolTaskExecutor执行比@Async要快。

线程池默认配置信息

可以在application.properties文件当中进行相关设置。

# 核心线程数
spring.task.execution.pool.core-size=8  
# 最大线程数
spring.task.execution.pool.max-size=16
# 空闲线程存活时间
spring.task.execution.pool.keep-alive=60s
# 是否允许核心线程超时
spring.task.execution.pool.allow-core-thread-timeout=true
# 线程队列数量
spring.task.execution.pool.queue-capacity=100
# 线程关闭等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 线程名称前缀
spring.task.execution.thread-name-prefix=task-

使用自定义的线程池

首先创建一个ThreadPoolConfig先配置一个线程池,并设置拒绝策略为CallerRunsPolicy

@Configuration
public class ThreadPoolConfig {

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数信息
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(200);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("myExecutor--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        //修改拒绝策略为使用当前线程执行
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }
}

然后执行之前写的测试代码发现,使用的线程池已经变成了自定义的线程池了

INFO 12740 — [ myExecutor–2] c.h.s.t.t.ThreadpoolApplicationTests : threadPoolTaskExecutor 创建线程 INFO 12740 — [ myExecutor–1] c.h.s.threadpool.threadpool.AsyncTest : 异步线程启动 started.async注解创建

如果配置多个线程池,该如何指定线程池呢?

@Configuration
public class ThreadPoolConfig {

       @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数信息
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(200);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("myExecutor--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        //修改拒绝策略为使用当前线程执行
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Bean("poolExecutor")
    public Executor poolExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //设置线程池参数信息
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(200);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("myExecutor2--");
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        taskExecutor.setAwaitTerminationSeconds(60);
        //修改拒绝策略为使用当前线程执行
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }
}

执行结果:

No qualifying bean of type ‘org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor’ available: expected single matching bean but found 2: taskExecutor,taskPoolExecutor

执行测试类,直接报错说找到多个类,不知道加载哪个类

由于测试类当中是这样自动注入的:

@Autowired
ThreadPoolTaskExecutor threadPoolTaskExecutor; 

考虑到@Autowired以及@Resources两个注入时的存在多个类如何匹配问题,所以只要在使用时指定要注入的bean就会调用相应的线程池。

 @Autowired
    AsyncTest asyncTest;
    @Autowired
    ThreadPoolTaskExecutor poolExecutor; //会去匹配 @Bean("poolExecutor") 这个线程池
    @Test
    void contextLoads() throws InterruptedException {
        asyncTest.hello("async注解创建");
        //一定要休眠 不然主线程关闭了,子线程还没有启动
        poolExecutor.submit(new Thread(()->{
            logger.info("threadPoolTaskExecutor 创建线程");
        }));
        Thread.sleep(1000);
    }

打印日志:

INFO 13636 — [ myExecutor2–1] c.h.s.t.t.ThreadpoolApplicationTests : threadPoolTaskExecutor 创建线程 INFO 13636 — [ myExecutor–1] c.h.s.threadpool.threadpool.AsyncTest : 异步线程启动 started.async注解创建

备注1:如果是使用@Async注解,只需要在注解里面指定bean的名称就可以切换对应的线程池去了,如下所示:

	@Async("taskPoolExecutor")
    public void hello(String name){
        logger.info("异步线程启动 started."+name);
    }

备注2:如果有多个线程池,但是在@Async注解里面没有指定的话,会默认加载第一个配置的线程池。

标签:task,Springboot,线程,注解,taskExecutor,Async,ThreadPoolTaskExecutor,public
来源: https://blog.csdn.net/qq_40093255/article/details/117020900