JDK中线程池参数详细解析

 

在jdk中为咱们提供了三种建立线程池的方式,可是在阿里的编码规范里面都是明确禁止使用这三种api去建立线程池,推荐咱们去自定义线程池。为何?api

 

要回答为何,咱们须要明白建立线程池时,各参数的做用:缓存

首先咱们来看一下jdk提供的建立线程池的三个api:编码

1. newFixedThreadPool    建立固定数量线程的线程池。spa

 

 

2. newSingleThreadExecutor   建立单线程的线程池线程

 

 3. newCachedThreadPool 建立一个带有缓存的线程池日志

 

 

发现这几种建立线程池的api,实质上都是依赖于ThreadPoolExecutor类来建立线程池。code

 

那咱们来看一下ThreadPoolExecutor 建立线程池时须要的参数,以及其做用。blog

 

建立一个线程池,须要7个参数。队列

1. corePoolSize: 线程池的核心线程数量。初始是不建立线程的。当有任务提交到线程池时,断定若是已经建立的线程数量小于核心数量,且没有空闲线程时,则会新建一个线程去执行新提交的任务。若是已经达到核心线程数量, 则会加入到阻塞队列中。内存

2.maximumPoolSize: 线程池的最大容量。当线程池的阻塞队列放满了, 而且线程数量还未达到线程池的最大线程数量, 则会建立新的线程,直到达到最大值

3.keepAliveTime   当阻塞队列里面的任务被执行完了, 且有空闲线程时,指定大于核心线程池数量的部分空闲线程的存活时间, 毕竟线程也是须要消耗资源的,及时回收颇有必要。当线程空闲的时间超过这个时间后,会回收掉一部分空闲线程,使其线程池中的线程数量不大于核心线程的数量

 4.unit  和keepAliveTIme 配套使用,上面指定了时间的数值,可是没有指定时间的单位(时,分,秒等), 这里须要指定时间的单位

5.workQueue  阻塞队列,当没有空闲线程时,多余的任务缓存的地方。

6.threadFactory 线程工厂,用来建立线程时,设定线程的一些参数。一般咱们为了后续查看日志方便,能够经过这个来指定咱们自定义的线程池的线程名称

7.handler  当线程数量达到最大值时,且阻塞队列慢了, 后续在提交任务时,没有地方能够接受继续的提交的任务。这种状况下的一个拒绝策略。

 

拒绝策略jdK,提供了四种:

// 由提交任务的线程执行任务
public
static class CallerRunsPolicy implements RejectedExecutionHandler { public CallerRunsPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
// 不在接收新的任务,直接抛出异常
public static class AbortPolicy implements RejectedExecutionHandler { public AbortPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
// 不接收也不抛出异常,空实现,忽略该任务
public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } } // 抛弃最老的任务,从阻塞队列中移除最先提交的任务,而后将该任务加入。 public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }

 

 

讲解完了建立线池时,各参数的做用,那么咱们如今再反过来看为何不让使用jdk提供的apI来建立线程池,而是须要咱们自定义线程池。

newFixedThreadPool ,newSingleThreadExecutor    这两种api 使用的阻塞队列都是无界队列,也就是不管有多少个任务来,咱们都接收。咱们的内存是有限的,阻塞队列里面存储的任务是越多,也就意味着占用的内存越多,这样会致使占用大量的内存,容易引发OOM

newCachedThreadPool  而这个api 的阻塞队列容量为0,最大线程数量为Integer 的最大值。每当有一个任务提交时,阻塞队列存储不了,就会新开启一个线程,当任务比较多,则会建立大量的线程, 引发OOM.

 

这就是为何咱们在使用线程池时必定要自定义线程池的缘由了。

相关文章
相关标签/搜索