Executors
都知道创建线程池可以使用工具类Executors,我们来看看调用Executors的方法时到底发生了什么,如果JDK提供的线程池不满足需求了,你会自己在JDK的基础上实现一个线程池吗?
从源码中可以看到调用newFixedThreadPool和newSingleThreadExecutor最终都是会创建ThreadPoolExecutor对象了,我们重要的就是研究下这个ThreadPoolExecutor了。ThreadPoolExecutor
ThreadPoolExecutor提供了四个构造方法,我们就看参数最多的那个。这里参数的含义其实也是基本上面试必问之一。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue
workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
先来看下下参数的含义,其实这些含义源码注释里面写的很清楚:
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
线程池维持的线程数量,即使他们空闲。也就是说这些线程是不会被回收的
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
线程数允许的最大数量。
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
超过corePoolSize数量的线程,如果在keepAliveTime时间内处于空闲时间,就会被关闭,当然会维持线程数值是corePoolSize。* @param unit the time unit for the {@code keepAliveTime} argument
keepAliveTime参数的单位
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
在任务执行之前, 使用队列用来装载任务。后面会解释线程池是怎么执行任务的,就知道这个队列是做啥用的了
* @param threadFactory the factory to use when the executor
* creates a new thread
创建线程使用的线程工厂类
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
当线程数量达到线程的边界以及队列的容量时,也就是说线程池满了,应该怎么处理这个线程,可以通过handler来定义。默认是RejectedExecutionHandler,会抛出RejectedExecutionException异常线程执行流程
为了方便,我们这里就调用5个参数的构造方法,其他两个参数一般使用默认的就好了
ThreadPoolExecutor pool = new ThreadPoolExecutor(
2, //核心的线程数量2
5, //最大的线程数量5
5, //空闲数值5分钟
TimeUnit.MINUTES, //空闲时间单位分钟
new ArrayBlockingQueue
(5) //使用有界队列
);
1、线程池初始化的时候会创建工作队列,设置一些参数,但是没有立即创建工作线程:
2、提交任务到线程池,这时候就会创建工作线程了,当提交了2个任务,还没超过corePoolSize的数量,都会立即创建工作线程的。图中是有2个工作线程的情况。
3、当第三个提交任务来的时候,但是前两个线程还是忙碌,就会把任务放在队列里面,等待线程池去取任务
4、当队列满了,就会创建线程直到线程数到最大线程数。图中编号是任务的执行顺序
5、当第9个任务来的时候,因为队列已满且达到了最大线程数,所以就会执行handler指定的策略,抛出RejectedExecutionException异常。
6、如果所有线程都空闲都到达闲置时间了,就会释放线程,但是会维持corePoolSize数量的线程数。
总结
因为方便画图,这里使用的有界队列,Executors里面使用的无界队列,也就是永远都不会达到maximumPoolSize的数量,不过源码里面都是设置corePoolSize等于maximumPoolSize的,所以我们平时要自己实现线程池的时候也可以把corePoolSize和maximumPoolSize的数量设置成一致。篇幅有限,就不再详细看源码了,大家按照这个思路自己去跟下源码。希望对大家有所帮助,有帮助记得点赞哦!可以关注下,后面持续分享架构文章,谢谢!
留言与评论(共有 0 条评论) |