场景
假设 需要使用多线程清理es中的历史数据
知识
参数解释:
- corePoolSize(核心线程数):线程池中的核心线程数量,即使线程池处于空闲状态,这些核心线程也不会被销毁。
- maximumPoolSize(最大线程数):线程池允许创建的最大线程数量。如果阻塞队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。
- keepAliveTime(非核心线程的空闲时间):非核心线程等待
keepAliveTime
时间后还没有获取到任务就会自动销毁。- unit(空闲时间单位):
keepAliveTime
的时间单位。- workQueue(任务队列):用于保存等待执行的任务的阻塞队列。
- ThreadFactory(线程工厂):用于创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,后期方便定位问题。
- RejectedExecutionHandler(拒绝策略):当线程池中的线程达到
maximumPoolSize
,说明线程池处于饱和状态,此时仍然有任务提交过来,那么必须采取一种策略处理提交的新任务。拒绝策略:当线程池中的线程达到最大数量,且任务队列已满时,需要采取一种策略来处理新提交的任务。
ThreadPoolTaskExecutor
提供了以下几种拒绝策略:
- AbortPolicy(默认拒绝策略):当实际线程数量大于维护队列中设定的数量时,将会触发拒绝任务的处理程序,它将抛出
RejectedExecutionException
。- DiscardPolicy:当实际线程数量大于维护队列中设定的数量时,新提交的任务将被静默丢弃。
- DiscardOldestPolicy:当实际线程数量大于维护队列中设定的数量时,队列中最老的任务将被静默丢弃,新任务将被放入队列。
- CallerRunsPolicy:当实际线程数量大于维护队列中设定的数量时,多出来的任务将由调用线程(主线程)处理。
实现方案
1.一个线程安全(保证时间段连贯)的参数生产方法(产生es 清理所需的时间段,索引,时间字段),定义一个外配置的json文件去做持久化记录时间段的位置(根据个人需要,完全可以摈弃)
2.一个es 清理的方法,我们用es的_delete_by_query 去处理
3.一个自定义线程池elasticsearchClearPool,定时任务去调用es 的清理方法 定时任务的线程为es-clear-main 清理的主线程,elasticsearchClearPool为es数据的清理的线程,
线程池的拒绝策略设置为:ThreadPoolExecutor.CallerRunsPolicy() (使用该策略保证清理时间的连贯性)
4.一个定时任务定时启动清理方法 使用fixedDelay 保证单一性
代码
只贴部分与文章相关的代码(存在冗余,使用按需改动即可)
自定义线程池配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concur