本篇内容介绍了“Java线程池ThreadPoolExecutor怎么创建”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
简介
ThreadPoolExecutor是一个实现ExecutorService接口的线程池,ExecutorService是主要用来处理多线程任务的一个接口,通常比较简单是用法是由Executors工厂类去创建。
线程池主要解决了两个不同的问题:

参数说明
ThreadPoolExecutor提供了几个核心参数,方便开发人员根据具体场景合理分配线程资源。
corePoolSize:核心线程数,在线程池创建时就已初始化好的n个核心线程,即使线程空闲着也会一直保留在线程池中不被销毁,除非调用线程池方法设置了java.util.concurrent.ThreadPoolExecutor#allowCoreThreadTimeOut(true)(允许核心线程超时销毁)。
maximumPoolSize:线程池允许存在最大线程数。
keepAliveTime:当线程数大于核心线程数时,多余的线程在执行任务结束后等待新任务的最大等待时间。
unit:TimeUnit类型,是keepAliveTime多余线程最大空余时间单位。
workQueue:必须指定一个阻塞队列,在线程池执行execute方法时新进来的任务在执行前都会保留到此队列里进入等待。
threadFactory:创建线程的工厂,默认采用Executors.defaultThreadFactory()创建线程。
handler:拒绝策略,当最大线程数已占满,且队列已满,此时线程池将触发拒绝策略,对新进来的任务做拒绝处理,具体的处理方案在后面详细分析(默认使用java.util.concurrent.ThreadPoolExecutor.AbortPolicy直接抛出异常拒绝处理)。
注:maximumPoolSize如果大于corePoolSize,则多出的部分线程数只有在阻塞队列workQueue占满时才会创建核心线程之外的线程去执行任务,如果我们设置的阻塞队列为无界队列(默认大小为Integer.MAX_VALUE),则队列永远无法占满,就不会去创建额外的线程进行工作,一般情况如果任务数足够,那么也是在队列大小还没达到Integer.MAX_VALUE时就已经出现内存溢出了。Executors线程池工厂中的newFixedThreadPool()、newSingleThreadExecutor()方法就是使用了无界队列LinkedBlockingQueue,防止内存溢出在日常开发过程中一般是不建议直接去使用Executors去创建线程池。
如何创建线程池
上面我们提到的可以使用Executors工厂直接创建线程池,但是Executors提供的创建线程池都是不可控的,我们还是得按自己的业务做好分析自定义一个线程池。
以下是线程池创建的一个案例:
@Slf4j
@Configuration
public class ThreadPoolConfig {
@Value("${threadPool.corePoolSize:8}")
private int corePoolSize;
@Value("${threadPool.maximumPoolSize:16}")
private int maximumPoolSize;
@Value("${threadPool.keepAliveTime:60}")
private int keepAliveTime;
@Value("${threadPool.queueSize:99999}")
private int queueSize;
@Bean
public ThreadPoolExecutor testExecutor() {
LinkedBlockingQueue queue = new LinkedBlockingQueue(queueSize);
return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
TimeUnit.SECONDS, queue, getThreadFactory(), getRejectedExecutionHandler());
}
/**
* 自定义线程池创建线程工厂,用于线程池创建线程的工厂
* @return
*/
private ThreadFactory getThreadFactory() {
return new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
log.info("===> Create new thread ...");
return new Thread(r);
}
};
}
/**
* 自定义拒绝策略,继续往队列里添加任务进入等待
* @return
*/
private RejectedExecutionHandler getRejectedExecutionHandler() {
return new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 继续往队列里添加任务,这里只是一个案例,这种方式并不友好,会抛出队列已满的异常
log.info("===> Handler runnable ......");
executor.getQueue().add(r);
}
};
}
}application.properties配置文件
threadPool:
corePoolSize: 8
maximumPoolSize: 16
keepAliveTime: 60
# 为方便测试这里我们配置队列数小一点
queueSize: 99
由以上的线程池配置,我们写一个demo测试一下:

截取部分运行日志:

注:可能有的同学会想线程池使用后需要销毁吗?在这里补充一下,如果我们是作为局部变量创建出来的线程池(如:在执行的方法内使用Executors.newFixedThreadPool(10)创建临时的线程池),这种情况我们用完就必须将它立即销毁,否则主线程就会一直处于运行状态。如果是全局配置的线程池,那么就是为整个系统中诸多业务提供使用的,这种就不需要对线程池做销毁,因为一旦销毁了其他的任务就无法继续使用该线程池执行任务。
拒绝策略
通常我们在配置好有限队列大小后,就会有可能出现队列占满的情况,这时候我们的拒绝策略就会起到作用,接下来我们就来分析一下RejectedExecutionHandler接口具体有哪一些实现方式:




private RejectedExecutionHandler getRejectedExecutionHandler() {
return new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 伪代码
log.info("===> 可根据任务的重要性区分对待,将任务做转换入库延迟处理 ......");
}
};
}“Java线程池ThreadPoolExecutor怎么创建”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注天达云网站,小编将为大家输出更多高质量的实用文章!