对于核心的几个线程池
newSingleThreadExecutor
newFixedThreadPool
newCachedThreadPool
其内部都是使用的ThreadPoolExecutor实现的,下面给出它们的实现方式:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
我们再来看看ThreadPoolExecutor的构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
}
参数说明:
corePoolSize:线程池中线程的数量
maximumPoolSize:线程池中最大的线程的数量
keepAliveTime:当线程池中线程的数量超过maximumPoolSize时,多余的空闲的线程的存活时间
unit:keepAliveTime的单位
workQueue:任务队列,存放已经提交但尚未被执行的任务
threadFactory:产生现成的工厂
handler:当任务太多来不及执行的时候的拒绝策略
重点介绍workQueue,它是一个BlockingQueue的接口的对象,根据队列的功能分类,可以使用下面几种BlockingQueue的实现:
1. SynchronousQueue,其没有容量,没进行一次put都必须等待一个相应的take,反之亦然,提交的任务不会被真实的保存,而总是将新任务提交给线程执行,如果没有空闲的线程并且线程数量还没有达到maximumPoolSize,则尝试创建新的线程,如果已经达到最大的线程数,那么就会执行拒绝策略
2. ArrayBlockingQueue,ArrayBlockingQueue必须包含一个参数,用于表示该队列的最大的容量,如果线程池的数量小于corePoolSize,那么提交任务后就会创建新的线程用于执行任务,如果线程池的数量大于corePoolSize,那么就会将任务假如等待队列ArrayBlockingQueue中,如果队列满了的话,线程池中线程的数量也没有达到maximumPoolSize,那么会创建新的线程执行任务,若大于了maxmium,那么就会执行拒绝策略。由此可见,ArrayBlockingQueue只有在队列满了的情况下,线程池中的线程数量才会突破corePoolSize个。
3. LinkedBlockingQueue,与有界队列ArrayBlockingQueue不一样的,除非系统资源耗尽,否则无界队列不存在任务入队失败的情况,当有新的任务进来的时候,如果线程池中线程的数量不足corePoolSize,那么会创建新的线程执行任务,但是当线程池中的线程的数量达到corePoolSize的时候,则任务就会直接进入到LinkedBlockingQueue中
在此,我们就不难发现为什么newFixedThreadPool实现的时候使用的是LinkedBlockingQueue,而newCachedThreadPool实现的时候使用的是SynchronousQueue。
拒绝策略
JDK内置的拒绝策略如下:
AbortPolicy:直接抛出异常
CallerRunsPolicy:直接在调用者的线程中,运行当前被丢弃的任务
DiscardOledestPolicy:丢弃掉最老的一个任务
DiscardPolicy:默默地丢弃无法处理的任务,不予任何处理
拒绝策略的源代码如下所示:
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}