javaDEMO
Java 基础 Demo 站: https://www.javastudy.cloud
Java 中高级开发博客: https://www.lixiang.red
Java 学习公众号: java 技术大本营
线程池创建的参数
在创建线程的各种方式中我们有讲到过通过创建线程池来完成异步操作,但实际上 jdk 提供的 Executors
来创建线程池都还有些缺陷,线程池有以下几个参数: 代码节选自源码 ThreadPoolExecutor.java 的构造函数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize: 线程池中线程的个数,最少的个数,即使是空闲的,也会存在
maximumPoolSize: 线程池中允许的连接的最大个数
keepAliveTime: corePoolSize 之外的线程,在没有任务时,最大存活时间
unit: keepAlveTime 的时间单位
workQueue: 在任务还没有执行前,保存 Runnable 任务的地方,也就是待执行任务队列
threadFactory: 线程工厂,可自定义线程生成的方式,可以自定义名字等等
handler:在线程池和队列满的时候,如何处理新到来的任务
jdk 自带线程池的缺陷
自带的线程池主要是通过 Executors 来初始化.
newCachedThreadPool
通过 Executors.newCachedThreadPool()初始化的线程池如下文所示,可以看到 maximumPoolSize 的值是 Integer.MAX_VALUE,这就意味着线程池里面的线程没有上限,会一直新建到 OOM.
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newFixedThreadPool
通过 Executors.newFixedThreadPool 新建的线程池,我们可以看到 workQueue 这个参数传的是 new LinkedBlockingQueue,这个队列没有设置大小,就会导致新任务会一直往里添加,直到 OOM
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
自定义线程池
通过对自带的线程池的分析,我们知道自定义的线程池主要是对池子的最大数量和等待队列的最大数量做好限制,当然还有息定义的失败策略(以后单写个 DEMO 讲)代码如下:
/**
* @author https://www.javastudy.cloud
*/
public class ThreadPoolTools {
/** 线程池维护线程的最少数量 */
private int minPoolSize = 10;
/** 线程池维护线程的最大数量 */
private int maxPoolSize = 500;
/** 线程池维护线程所允许的空闲时间 */
private int idleSeconds = 1800;
/** 线程池所使用的缓冲队列 */
private int queueBlockSize = 100;
private ThreadPoolExecutor executor;
public ThreadPoolTools() {
this.executor = new ThreadPoolExecutor(minPoolSize, maxPoolSize, idleSeconds,
TimeUnit.SECONDS, /* 时间单位,秒 */
new ArrayBlockingQueue<Runnable>(queueBlockSize),
new ThreadPoolExecutor.CallerRunsPolicy()); /* 重试添加当前加入失败的任务 */
}
public void execute(Runnable task) {
executor.execute(task);
}
public <T> Future<T> submit(Callable<T> task){
return executor.submit(task);
}
}
DEMO 总评
线程池的使用在实际开发中用到的还是挺多的,在小型开发中使用系统自带的线程池是没问题的,但有时候在生产环境中,特别是同步一些东西的时候,量级比较大,这时候使用系统自带的线程池难免会有些问题,这时候就需要自定义的线程池了,加油吧,少年!!
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于