线程池创建的七种方式
|____________________________________________________________________________________________________
| I Executor |
| / |
|I ExcutorService、I ScheduledExecutorService |
| | |
| | |
| AbstractExecutorService |
| \ |
| 1.ThreadPoolExecutor (最原始的线程池创建方式,2~4 是基于1的封装) |
|----------------------------------------------------------------------------------------------------|
| Executors |
| |--2.newSingleThreadExecutor() //创建单线程池 |
| |--3.newCachedThreadPool() //适用大量短时任务,池子可伸缩,工作队列为SynchronousQueue |
| |--4.newFixedThreadPool(int nThreads) //创建n线程池 |
| | |
| |--5.newSingleThreadScheduledExecutor() //创建单线程池,可以进行定时或周期性的工作调度 |
| |--6.newScheduledThreadPool(int corePoolSize)//创建n线程池,可以进行定时或周期性的工作调度 |
| | |
| |--7.newWorkStealingPool(int parallelism)//jdk8 引入 |
|____________________________________________________________________________________________________|
ThreadPoolExecutor(核心类)
/**
*ThreadPoolExecutor|--核心线程数
* |--最大线程数
* |--存活时间
* |--时间单位
* |--工作队列(阻塞队列)
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
Executors.defaultThreadFactory(),
defaultHandler);
}
BlockingQueue(常用工作队列)
|
|--1.ArrayBlockingQueue //内部基于数组来存放元素,一个典型的“固定有界缓存区”,一旦创建,就不能再增加其容量。
|--2.DelayBlockingQueue _/\ //一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能到期时才能从队列中取走
|--3.LinkedBlockingQueue | //内部基于链表来存放元素,如果不指定容量,默认为Integer.MAX_VALUE,也就是无界队列
|--4.PriorityBlockingQueue | //保证每次取出的元素都是队列中权值最小的,即通过完全二叉树实现的小顶堆
|--5.SynchronousQueue | //它内部没有容器,来一个任务则创建一个线程,池子无法承受时会拒绝任务
|
PriorityQueue
阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。
同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止。
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E>
DelayQueue阻塞队列在我们系统开发中也常常会用到,底层使用的是PriorityQueue
例如:缓存系统的设计,缓存中的对象,超过了空闲时间,需要从缓存中移出;
任务调度系统,能够准确的把握任务的执行时间。
SynchronousQueue 也是一个队列来的,但它的特别之处在于它内部没有容器,一个生产线程,当它生产产品(即put的时候),
如果当前没有人想要消费产品(即当前没有线程执行take),此生产线程必须阻塞,等待一个消费线程调用take操作,
take操作将会唤醒该生产线程,同时消费线程会获取生产线程的产品(即数据传递)
submit 和 execute的区别
1、submit()方法中参数可以是Callable类型也可以是Runnable类型,而execute()方法参数只能是Runnable类型。
2、submit有返回值,而execute没有
用到返回值的例子,比如说我有很多个做validation的task,我希望所有的task执行完,然后每个task告诉我它的执行结果,是成功还是失败,
如果是失败,原因是什么。然后我就可以把所有失败的原因综合起来发给调用者。cancel execution这个用处不大,很少有需要去取消执行的。
3、Callable 类型的任务可以获取执行的返回值,而 Runnable 执行无返回值;submit方便Exception处理;
意思就是如果你在你的task里会抛出checked或者unchecked exception,
而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过捕获Future.get抛出的异常。
|-----------------------------------------------------------------------|
| public Future<?> submit(Runnable task) { |
| if (task == null) throw new NullPointerException(); |
| RunnableFuture<Void> ftask = newTaskFor(task, null); |
| execute(ftask); |
| return ftask; |
| } |
|-----------------------------------------------------------------------|
| public <T> Future<T> submit(Runnable task, T result) { |
| if (task == null) throw new NullPointerException(); |
| RunnableFuture<T> ftask = newTaskFor(task, result); |
| execute(ftask); |
| return ftask; |
| } |
|-----------------------------------------------------------------------|
| public <T> Future<T> submit(Callable<T> task) { |
| if (task == null) throw new NullPointerException(); |
| RunnableFuture<T> ftask = newTaskFor(task); |
| execute(ftask); |
| return ftask; |
| } |
|-----------------------------------------------------------------------|
RejectedExecutionHandler(线程池拒绝策略:调用具体handler的rejectedExecution方法)
|
|-前置条件:当一个任务通过execute(Runnable)方法欲添加到线程池时
| |
| |--l.如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
| |
| |--2.如果此时线程池中的数量等于corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
| |
| |--3.如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
| |
| |--4.如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
| | 也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
|
|-四种拒绝策略|--1.RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();//这个是默认策略
| |-- 此策略 :将抛出 RejectedExecutionException.
| |-- 源码如下:public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
| | throw new RejectedExecutionException("Task "
| | + r.toString()
| | +" rejected from"
| | +e.toString());
| | }
| |
| |--2.RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
| |-- 此策略 :用于被拒绝任务的处理程序,它直接执行被拒绝的任务;如果线程池已关闭,则会丢弃该任务。
| |-- 源码如下:public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
| | if (!e.isShutdown()) {
| | r.run();
| | }
| | }
| |
| |--3.RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
| |-- 此策略 :首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。
| |-- 源码如下:public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
| | if (!e.isShutdown()) {
| | e.getQueue().poll();
| | e.execute(r);
| | }
| | }
| |
| |--4.RejectedExecutionHandler handler = ThreadPoolExecutor.DiscardPolicy();
| |-- 此策略 :什么也不做,之间丢弃;
| |-- 源码如下: /**
| | * Does nothing, which has the effect of discarding task r.
| | * @param r the runnable task requested to be executed
| | * @param e the executor attempting to execute this task
| | */
| | public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
| | }