线程池原理
线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。他的主要特点为:
线程复用
每一个Thread
类都有一个start
方法,当调用start
方法启用线程时Java虚拟机会调用线程的run
方法。Thread
类的run()
方法其实就是调用了Runable
对象的run()
方法。我们可以继承重写Thread
类,在其start
方法中添加不断循环调用传递过来的Runnable
对象。这就是线程池的实现原理。循环方法中不断获取Runable
是用Queue
实现的,在获取下一个Runnable
之前可以是阻塞的。
图 1 线程池在Jdk中主要涉及的类及方法汇总
线程池的组成
一般线程池主要分为以下四个组成部分:
Java 中的线程池是通过 Executor
框架实现的,该框架中用到了 Executor,Executors,ExecutorService,ThreadPoolExecutor ,Callable 和 Future、FutureTask
这几个类。
ThreadPoolExecutor
的构造方法如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize,
keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(),
defaultHandler);
}
拒绝策略
线程池中的线程已经用完了,无法继续为新任务服务,同时,等待队列也已经排满了,再也塞不下新任务了。这时候我们就需要拒绝策略机制合理的处理这个问题。
JDK 内置的拒绝策略如下:
AbortPolicy
: 直接抛出异常,阻止系统正常运行CallerRunsPolicy
: 只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。显然这样做不会真的丢弃任务,但是,DiscardPolicy
: 该策略默默地丢弃无法处理的任务,不予任何处理。如果允许任务丢失,这是最好的一种方案。以上内置拒绝策略均实现了 RejectedExecutionHandler
接口,若以上策略仍无法满足实际需要,完全可以自己扩展 RejectedExecutionHandler
接口。
Java线程池的工作过程
2.调用execute()
方法添加一个任务时,线程池会作如下判断:
a) 如果正在运行的线程数量小于 corePoolSize
,那么马上创建线程运行这个任务;
b) 如果正在运行的线程数量大于等于corePoolSize
,那么将这个任务放入队列;
c) 如果这个时候队列满了,而且此时正在运行的线程数量小于maximumPoolSize
,那么还是要创建非核心线程继续运行这个任务;
d) 如果队列满了,而且线程池中运行的线程数大于等于maximumPoolSize
,那么线程池会抛出RejectExecutionException
。
corePoolSize
,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize
的大小。图 2 线程池工作过程流程图
说明:本文内容取自行业内大佬整理的《2020最新Java面试题及答案》,非原创。
---END---