ThreadPoolExecutor构造函数
一.
(1)
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue){
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
(2)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
(3)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
(4)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
ThreadPoolExecutor线程连接池总共四个函数,可以看到前面三个构造函数都是传入一系列的参数然后调用第四个构造函数,其实起作用的就最后一个构造函数。
分别来看看构造函数(第四个)中每个参数所代表的意思:
corePoolSize:以为核心线程池
线程池中的主力线程,当一个任务到来的时候,首先调用核心线程来运行
maximumPoolSize:线程池中最大的线程数
线程池中除了核心线程之外还可以启动普通的线程,什么时候启动呢?接着看
keepAliveTime:线程存活时间
线程空闲的时候,线程存活的时间
TimeUnit:keepAliveTime的时间单位
取值有:
TimeUnit.DAYS(天)
TimeUnit.HOURS(时)
TimeUnit.MICROSECONDS(微秒)
TimeUnit.MILLISECONDS(毫秒)
TimeUnit.MINUTES(分)
TimeUnit.NANOSECONDS(毫微秒)
TimeUnit.SECONDS (秒)
BlockingQueue<Runnable>:阻塞队列的接口
当所有核心线程都在工作的时候,新进来的任务就会进入阻塞队列中
常用的有:
ArrayBlockingQueue bounded(有界) 加锁 arrayList
LinkedBlockingQueue optionally-bounded 加锁 linkedList
PriorityBlockingQueue unbounded 加锁 heap
DelayQueue unbounded 加锁 heap
SynchronousQueue bounded 加锁 无
LinkedTransferQueue unbounded 加锁 heap
LinkedBlockingDeque unbounded 无锁 heap
ArrayBlockingQueue:是一个用数组实现的有界阻塞队列,此队列按照先进先出(FIFO)的原则对元素进行排序。支持公平锁和非公平锁。【注:每一个线程在获取锁的时候可能都会排队等待,如果在等待时间上,先获取锁的线程的请求一定先被满足,那么这个锁就是公平的。反之,这个锁就是不公平的。公平的获取锁,也就是当前等待时间最长的线程先获取锁】
LinkedBlockingQueue:一个由链表结构组成的有界队列,此队列的长度为Integer.MAX_VALUE。此队列按照先进先出的顺序进行排序。
PriorityBlockingQueue: 一个支持线程优先级排序的无界队列,默认自然序进行排序,也可以自定义实现compareTo()方法来指定元素排序规则,不能保证同优先级元素的顺序。
DelayQueue: 一个实现PriorityBlockingQueue实现延迟获取的无界队列,在创建元素时,可以指定多久才能从队列中获取当前元素。只有延时期满后才能从队列中获取元素。(DelayQueue可以运用在以下应用场景:1.缓存系统的设计:可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。2.定时任务调度:使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,从比如TimerQueue就是使用DelayQueue实现的。)
SynchronousQueue: 一个不存储元素的阻塞队列,每一个put操作必须等待take操作,否则不能添加元素。支持公平锁和非公平锁。SynchronousQueue的一个使用场景是在线程池里。Executors.newCachedThreadPool()就使用了SynchronousQueue,这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程空闲了60秒后会被回收。
LinkedTransferQueue: 一个由链表结构组成的无界阻塞队列,相当于其它队列,LinkedTransferQueue队列多了transfer和tryTransfer方法。
LinkedBlockingDeque: 一个由链表结构组成的双向阻塞队列。队列头部和尾部都可以添加和移除元素,多线程并发时,可以将锁的竞争最多降到一半。原文
ThreadFactory :线程产生工厂(可像下方一样自定义)
new ThreadFactory() {
public Thread newThread(Runnable r) {
return null;
}
}
RejectedExecutionHandler :线程池无法提供线程处理任务时的策略
取值有:
AbortPolicy
该策略是线程池的默认策略。使用该策略时,如果线程池队列满了,已经产生的线程已经到达了maximumPoolSize这个值(maximumPoolSize=核心线程+新创建的线程)则丢掉新来的任务并且抛出RejectedExecutionException异常。
DiscardPolicy
这个策略和AbortPolicy的slient版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常。
DiscardOldestPolicy
这个策略从字面上也很好理解,丢弃最老的。也就是说如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列。
因为队列是队尾进,队头出,所以队头元素是最老的,因此每次都是移除对头元素后再尝试入队。
CallerRunsPolicy
使用此策略,如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行。就像是个急脾气的人,我等不到别人来做这件事就干脆自己干。
那么线程池什么时候使用核心线程执行,什么时候将任务加入阻塞队列,什么时候新创建普通的线程来处理任务呢?
1.当线程池中的线程还没有达到corePoolSize数量的时候,新提交的任务会启动一个corePoolSize的线程执行。
2.当线程池中的线程数达到了corePoolSize的数量,这部分的线程就叫做核心线程,那么新来的任务之后加入阻塞队列中等待,等待有某个核心线程空闲了,再调用核心线程执行。
3.当阻塞队列满了,那么这个时候对于新进来的任务线程池就会启动普通线程进行执行。
4.当启动的核心线程+普通线程>maximumPoolSize,这个时候就会根据所采用的策略进行相应的处理(报错,报错丢弃,不报错丢弃,调用者线程执行)
keepAliveTime:这个参数的主要作用是:
当有普通线程被启动执行任务,任务执行完了,那么经过keepAliveTime时间,普通线程就会被摧毁。对于核心线程来说,如果没有显式设置Executor.allowCoreThreadTimeOut(true),那么空闲的核心线程经过keepAliveTime时间是不会被摧毁的。new LinkedBlockingQueue():当使用这个阻塞队列没有,而且没有给这个构造函数一个长度参数,那么keepAliveTime是不起作用的,即阻塞队列可以无限添加任务,而不会启动新的普通线程执行任务。