什么是线程池?
线程池顾名思义就是放线程的池子,和数据库连接池类似.当我们需要线程时,我们就从池中拿一个,
不需要通过new Thread()
的方式来创建.那有的人就说,我使用new Thread()这种方式也能创建线程,
为什么要使用线程池呢?
用new Thread()肯定是可以的,但是它带来了一些缺点,主要有两点:
(1)效率低
(2)不方便管理.
这两点正是线程池带来的好处.
如何使用
在JDK中主要可以使用ThreadPoolExecutor和Executors来创建线程池,ThreadPoolExecutor可以手动创建线程池,
设置更加灵活。而Executors它可以创建默认属性的线程池,例如固定大小的线程池,可以缓存的线程池等等。这篇我主要讲ThreadPoolExecutor
1.构造函数
主要有四个构造函数,我选取一个入参最多的来说吧。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:
核心线程大小。需要注意的是在初创建线程池时线程不会立即启动,直到有任务提交才开始启动线程并逐渐时线程数目达到corePoolSize.
若想一开始就创建所有核心线程需调用prestartAllCoreThreads方法.默认情况下,核心线程数会一直存活,不会受到keepAliveTime的限制,除非手动设置allowCoreThreadTimeOut为true.
maximumPoolSize:
池中允许的最大线程数。需要注意的是,如果当前线程池的线程数等于corePoolSize,再提交任务,会被放入到workQueue队列,当workQueue队列满了之后,
只有当workQueue满了之后,才会再创建新的线程。如果当前线程数量超过maximumPoolSize,会执行RejectedExecutionHandler策略。
keepAliveTime:
非核心线程的闲置超时时间,超过这个时间就会被回收。
unit:
时间单位
workQueue:
线程池中的任务队列.如果是无界队列,maximumPoolSize参数就不会起作用。
threadFactory:
线程工厂,提供创建新线程的功能。
handler:
饱和策略.主要有四种:
(一)AbortPolicy中止策略-默认的策略.该策略直接抛出异常
/**
* The default rejected execution handler
*/
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
(二)DiscardPolicy抛弃策略-该策略什么都不做,相当于删除任务。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
(三)DiscardOldestPolicy抛弃旧任务策略-先将阻塞队列中的头元素出队抛弃,再尝试提交任务。如果此时阻塞队列使用PriorityBlockingQueue优先级队列,将会导致优先级最高的任务被抛弃,因此不建议将该种策略配合优先级队列使用
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
(四)CallerRunsPolicy调用者运行-既不抛弃任务也不抛出异常,直接运行任务的run方法,换言之将任务回退给调用者来直接运行。使用该策略时线程池饱和后将由调用线程池的主线程自己来执行任务,因此在执行任务的这段时间里主线程无法再提交新任务,从而使线程池中工作线程有时间将正在处理的任务处理完成
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
2.流程
poolSize:线程池中当前线程的数量
corePoolSize:核心线程池大小
maximumPoolSize:池中允许的最大线程数
当新提交一个任务时:
(1)如果poolSize<corePoolSize,新增加一个线程处理新的任务。
(2)如果poolSize=corePoolSize,新任务会被放入阻塞队列等待。
(3)如果阻塞队列的容量达到上限,且这时poolSize<maximumPoolSize,新增线程来处理任务。
(4)如果阻塞队列满了,且poolSize=maximumPoolSize,那么线程池已经达到极限,会根据不同策略做不同处理。
在实际使用中,需要根据自己业务要求,设置合理参数
网友评论