SpringBoot—自定义线程池及并发定时任务模板
介绍
在项目开发中,经常遇到定时任务,今天通过自定义多线程池总结一下SpringBoot默认实现的定时任务机制。
定时任务模板
pom依赖
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	//线程池用到
	<dependency>
    	<groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>22.0</version>
    </dependency>
    //@Slf4j注解用到
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
        <version>1.18.4</version>
    </dependency>
</dependencies>
自定义线程池模板
package com.example.andya.demo.conf;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.*;
/**
 * @author Andya
 * @create 2020-05-29 14:08
 */
@Configuration
public class ThreadPoolConfig {
    public static String THREAD_NAME = "first-thread-pool-%d";
    public static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2 + 1;
    public static int MAX_POOL_SIZE = 10;
    public static int QUEUE_SIZE = 10;
    /**
     * 自定义消费队列线程池
     *
     * @return
     */
    @Bean(value = "firstThreadPool")
    public ExecutorService buildFirstThreadPool() {
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(THREAD_NAME).build();
        /**
         * 1. CallerRunsPolicy :    这个策略重试添加当前的任务,他会自动重复调用 execute() 方法,直到成功。
         2. AbortPolicy :         对拒绝任务抛弃处理,并且抛出异常。
         3. DiscardPolicy :       对拒绝任务直接无声抛弃,没有异常信息。
         4. DiscardOldestPolicy : 对拒绝任务不抛弃,而是抛弃队列里面等待最久的一个线程,然后把拒绝任务加到队列。
         */
        ExecutorService threadPool = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                0L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(QUEUE_SIZE),
                threadFactory,
                new ThreadPoolExecutor.AbortPolicy());
        return threadPool;
    }
}
定时任务模板
package com.example.andya.demo.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
/**
 * @author Andya
 * @create 2020-05-29 14:26
 */
@Service
@EnableScheduling
@Slf4j
public class TestThreadPool {
    @Resource(name = "firstThreadPool")
    private ExecutorService firstThreadPool;
    @Scheduled(cron = "0 * * * * *")
    public void test1SchedulerThreadPool() {
        final CountDownLatch countDownLatch = new CountDownLatch(5);
        log.info("Begin schedule-【1】 startTime: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        for (int i = 0; i < 5; i++) {
            firstThreadPool.execute(() -> {
                countDownLatch.countDown();
                log.info("schedule-【1】 , threadPool info: {}, countDownLatch info: {}", firstThreadPool.toString(), countDownLatch.toString());
            });
        }
        try {
            countDownLatch.await(5, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            log.error("schedule-【1】timeout, {}", e.getMessage());
        } finally {
            log.info("schedule-【1】 multi-threading countDownLatch count: {}",  countDownLatch.getCount());
        }
        log.info("End schedule-【1】 startTime: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
    @Scheduled(cron = "0 * * * * *")
    public void test2SchedulerThreadPool() {
        final CountDownLatch countDownLatch = new CountDownLatch(5);
        log.info("Begin schedule-【2】 startTime: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        for (int i = 0; i < 5; i++) {
            firstThreadPool.execute(() -> {
                countDownLatch.countDown();
                log.info("schedule-【2】, threadPool info {}, countDownLatch info: {}", firstThreadPool.toString(), countDownLatch.toString());
            });
        }
        try {
            countDownLatch.await(5, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            log.error("schedule-【2】timeout, {}", e.getMessage());
        } finally {
            log.info("schedule-【2】 multi-threading countDownLatch count: {}",  countDownLatch.getCount());
        }
        log.info("End schedule-【2】 startTime: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
}
运行结果
2020-05-29 15:45:00.011  INFO 6900 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : Begin schedule-【2】 startTime: 2020-05-29 15:45:00
2020-05-29 15:45:00.018  INFO 6900 --- [t-thread-pool-0] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0], countDownLatch info: java.util.concurrent.CountDownLatch@522af59c[Count = 4]
2020-05-29 15:45:00.019  INFO 6900 --- [t-thread-pool-1] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 5, active threads = 4, queued tasks = 0, completed tasks = 1], countDownLatch info: java.util.concurrent.CountDownLatch@522af59c[Count = 3]
2020-05-29 15:45:00.019  INFO 6900 --- [t-thread-pool-2] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 5, active threads = 3, queued tasks = 0, completed tasks = 2], countDownLatch info: java.util.concurrent.CountDownLatch@522af59c[Count = 2]
2020-05-29 15:45:00.019  INFO 6900 --- [t-thread-pool-3] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 5, active threads = 2, queued tasks = 0, completed tasks = 3], countDownLatch info: java.util.concurrent.CountDownLatch@522af59c[Count = 1]
2020-05-29 15:45:00.019  INFO 6900 --- [t-thread-pool-4] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 5, active threads = 1, queued tasks = 0, completed tasks = 4], countDownLatch info: java.util.concurrent.CountDownLatch@522af59c[Count = 0]
2020-05-29 15:45:00.019  INFO 6900 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : schedule-【2】 multi-threading countDownLatch count: 0
2020-05-29 15:45:00.019  INFO 6900 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : End schedule-【2】 startTime: 2020-05-29 15:45:00
2020-05-29 15:45:00.020  INFO 6900 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : Begin schedule-【1】 startTime: 2020-05-29 15:45:00
2020-05-29 15:45:00.021  INFO 6900 --- [t-thread-pool-0] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 9, active threads = 5, queued tasks = 0, completed tasks = 5], countDownLatch info: java.util.concurrent.CountDownLatch@5ced01a9[Count = 4]
2020-05-29 15:45:00.023  INFO 6900 --- [t-thread-pool-5] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 9, active threads = 4, queued tasks = 0, completed tasks = 6], countDownLatch info: java.util.concurrent.CountDownLatch@5ced01a9[Count = 3]
2020-05-29 15:45:00.024  INFO 6900 --- [t-thread-pool-6] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 9, active threads = 3, queued tasks = 0, completed tasks = 7], countDownLatch info: java.util.concurrent.CountDownLatch@5ced01a9[Count = 2]
2020-05-29 15:45:00.024  INFO 6900 --- [t-thread-pool-7] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 9, active threads = 3, queued tasks = 0, completed tasks = 7], countDownLatch info: java.util.concurrent.CountDownLatch@5ced01a9[Count = 1]
2020-05-29 15:45:00.025  INFO 6900 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 multi-threading countDownLatch count: 0
2020-05-29 15:45:00.025  INFO 6900 --- [t-thread-pool-8] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@26b894bd[Running, pool size = 9, active threads = 3, queued tasks = 0, completed tasks = 7], countDownLatch info: java.util.concurrent.CountDownLatch@5ced01a9[Count = 0]
2020-05-29 15:45:00.025  INFO 6900 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : End schedule-【1】 startTime: 2020-05-29 15:45:00
从上述结果中可以看出,虽然是test1SchedulerThreadPool()和test2SchedulerThreadPool()都是每分钟执行定时任务,但是明显两个方法没有并发执行,而是串行执行的。
并发定时器模板
通过增加一个配置类来并发执行定时任务。
package com.example.andya.demo.conf;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
/**
 * @author Andya
 * @create 2020-05-29 15:52
 */
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
    }
}
运行结果
2020-05-29 15:53:00.005  INFO 3028 --- [pool-2-thread-2] c.e.andya.demo.service.TestThreadPool    : Begin schedule-【2】 startTime: 2020-05-29 15:53:00
2020-05-29 15:53:00.015  INFO 3028 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : Begin schedule-【1】 startTime: 2020-05-29 15:53:00
2020-05-29 15:53:00.019  INFO 3028 --- [t-thread-pool-0] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 9, queued tasks = 1, completed tasks = 0], countDownLatch info: java.util.concurrent.CountDownLatch@630f649f[Count = 3]
2020-05-29 15:53:00.020  INFO 3028 --- [t-thread-pool-3] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 9, queued tasks = 1, completed tasks = 0], countDownLatch info: java.util.concurrent.CountDownLatch@630f649f[Count = 1]
2020-05-29 15:53:00.019  INFO 3028 --- [t-thread-pool-1] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 9, queued tasks = 1, completed tasks = 0], countDownLatch info: java.util.concurrent.CountDownLatch@630f649f[Count = 3]
2020-05-29 15:53:00.019  INFO 3028 --- [t-thread-pool-2] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 9, queued tasks = 1, completed tasks = 0], countDownLatch info: java.util.concurrent.CountDownLatch@630f649f[Count = 2]
2020-05-29 15:53:00.021  INFO 3028 --- [t-thread-pool-0] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 6, queued tasks = 0, completed tasks = 4], countDownLatch info: java.util.concurrent.CountDownLatch@5ebb120e[Count = 4]
2020-05-29 15:53:00.021  INFO 3028 --- [t-thread-pool-4] c.e.andya.demo.service.TestThreadPool    : schedule-【2】, threadPool info java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 5, queued tasks = 0, completed tasks = 5], countDownLatch info: java.util.concurrent.CountDownLatch@630f649f[Count = 0]
2020-05-29 15:53:00.021  INFO 3028 --- [pool-2-thread-2] c.e.andya.demo.service.TestThreadPool    : schedule-【2】 multi-threading countDownLatch count: 0
2020-05-29 15:53:00.022  INFO 3028 --- [pool-2-thread-2] c.e.andya.demo.service.TestThreadPool    : End schedule-【2】 startTime: 2020-05-29 15:53:00
2020-05-29 15:53:00.022  INFO 3028 --- [t-thread-pool-5] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 4, queued tasks = 0, completed tasks = 6], countDownLatch info: java.util.concurrent.CountDownLatch@5ebb120e[Count = 3]
2020-05-29 15:53:00.022  INFO 3028 --- [t-thread-pool-6] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 3, queued tasks = 0, completed tasks = 7], countDownLatch info: java.util.concurrent.CountDownLatch@5ebb120e[Count = 2]
2020-05-29 15:53:00.024  INFO 3028 --- [t-thread-pool-7] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 2, queued tasks = 0, completed tasks = 8], countDownLatch info: java.util.concurrent.CountDownLatch@5ebb120e[Count = 1]
2020-05-29 15:53:00.024  INFO 3028 --- [t-thread-pool-8] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 , threadPool info: java.util.concurrent.ThreadPoolExecutor@5149f008[Running, pool size = 9, active threads = 2, queued tasks = 0, completed tasks = 8], countDownLatch info: java.util.concurrent.CountDownLatch@5ebb120e[Count = 0]
2020-05-29 15:53:00.024  INFO 3028 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : schedule-【1】 multi-threading countDownLatch count: 0
2020-05-29 15:53:00.024  INFO 3028 --- [pool-2-thread-1] c.e.andya.demo.service.TestThreadPool    : End schedule-【1】 startTime: 2020-05-29 15:53:00
可以从运行结果中看到,test1SchedulerThreadPool()和test2SchedulerThreadPool()两个方法同时打印了Begin schedule...信息,是并发定时。
SpringBoot—自定义线程池及并发定时任务模板的更多相关文章
- SpringBoot自定义线程池处理异步任务
		
@Async异步调用 就不解释什么是异步调用了,Spring Boot中进行异步调用很简单 1.通过使用@Async注解就能简单的将原来的同步函数变为异步函数 package com.winner.s ...
 - SpringBoot 自定义线程池
		
本教程目录: 自定义线程池 配置spring默认的线程池 1. 自定义线程池 1.1 修改application.properties task.pool.corePoolSize=20 task.p ...
 - SpringBoot 自定义线程池,多线程
		
原文:https://www.jianshu.com/p/832f2b162450 我们都知道spring只是为我们简单的处理线程池,每次用到线程总会new 一个新的线程,效率不高,所以我们需要自定义 ...
 - JAVA并发,线程工厂及自定义线程池
		
package com.xt.thinks21_2; import java.util.concurrent.ExecutorService; import java.util.concurrent. ...
 - Spring Boot使用@Async实现异步调用:自定义线程池
		
前面的章节中,我们介绍了使用@Async注解来实现异步调用,但是,对于这些异步执行的控制是我们保障自身应用健康的基本技能.本文我们就来学习一下,如果通过自定义线程池的方式来控制异步调用的并发. 定义线 ...
 - 转载-SpringBoot结合线程池解决多线程问题实录;以及自己的总结
		
原文地址:https://blog.csdn.net/GFJ0814/article/details/92422245 看看这篇文章(继续学习):https://www.jianshu.com/p/3 ...
 - Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
		
前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...
 - Android 自定义线程池的实战
		
前言:在上一篇文章中我们讲到了AsyncTask的基本使用.AsyncTask的封装.AsyncTask 的串行/并行线程队列.自定义线程池.线程池的快速创建方式. 对线程池不了解的同学可以先看 An ...
 - spring boot / cloud (四) 自定义线程池以及异步处理@Async
		
spring boot / cloud (四) 自定义线程池以及异步处理@Async 前言 什么是线程池? 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线 ...
 
随机推荐
- ln命令:软链接与硬链接的区别与应用
			
ln命令:软链接与硬链接的区别与应用 摘要 Linux系统中,链接是一个十分常见且实用的文件处理命令,它分为软链接和硬链接两种类型.软链接类似于Windows中的快捷方式,硬链接又有着与原文件保持同步 ...
 - 你真的会用Flutter日期类组件吗
			
Flutter系统提供了一些日期选择类组件,比如DayPicker.MonthPicker.YearPicker.showDatePicker.CupertinoDatePicker等,其中前4个为M ...
 - java基础篇 之 foreach探索
			
我们看下这段代码: public class Main { public static void main(String[] args) { List list = new ArrayList(); ...
 - Spring Cloud 系列之 Config 配置中心(一)
			
服务配置现状 配置文件是我们再熟悉不过的,在微服务系统中,每个微服务不仅仅只有代码,还需要连接其他资源,例如数据库的配置或功能性的开关 MySQL.Redis .Security 等相关的配置.除了项 ...
 - 【Hadoop离线基础总结】MapReduce案例之自定义groupingComparator
			
MapReduce案例之自定义groupingComparator 求取Top 1的数据 需求 求出每一个订单中成交金额最大的一笔交易 订单id 商品id 成交金额 Order_0000005 Pdt ...
 - python工业互联网应用实战1—SQL与ORM
			
从sql到ORM应该说也是编程体系逐步演化的结果,通过类和对象更好的组织开个过程中遇到的各种业务问题,面向对象的解耦和内聚作为一套有效的方法论,对于复杂的企业应用而言确实能够解决实践过程中很多问题. ...
 - Mybatis 分页:Pagehelper + 拦截器实现
			
一.分页插件 Pagehelper PageHelper是Mybatis的一个分页插件,非常好用! 1.1 Spring Boot 依赖 <!-- pagehelper 分页插件--> & ...
 - 帝国cms列表页内容简介字段smalltext去除里面html格式代码 设置方法
			
帝国cms列表页内容简介字段smalltext去除里面html格式代码帝国cms列表页调用内容简介出现html代码怎么办 近来在用帝国cms的时候,发现一个问题,在列表页调用产品简介的时候出现了这种h ...
 - Vue中跨域问题解决方案1
			
我们需要配置代理.代理可以解决的原因:因为客户端请求服务端的数据是存在跨域问题的,而服务器和服务器之间可以相互请求数据,是没有跨域的概念(如果服务器没有设置禁止跨域的权限问题),也就是说,我们可以配置 ...
 - 基于Nettty打造自己的MVC服务器
			
最近开始折腾Netty,体验下NIO编程.既然学习了,就要做点东西出来,要不然不容易掌握学到的东西.在Netty的官方demo上都有各种case的sample,打造Http服务器的核心代码就是从Sam ...