JDK里的几种线程池
先看下一个ThreadPoolExecutor通用的构造函数,有8个参数。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
下面介绍下每个参数的具体含义
corePoolSize:线程池的基本大小,即在没有任务执行的情况时线程池的大小。
maximumPoolSize: 线程池的最大大小,,表示可同时活动的线程数量的上限。
keepAliveTime: 线程的存活时间,如果某个线程的空闲时间超过了存活时间并且当前线程池大小大于corePoolSize时,那么将被标记为可回收。
TimeUnit unit:存活时间的时间单位
BlockingQueue workQueue: 如果请求的到达速率超过了线程池的处理速率,那么新到来的线程将在该队列中等待。基本的任务排队方法有3中:无界队列,有界队列和同步移交。
ThreadFactory :线程工厂,当线程池需要创建一个线程时,通过线程工厂方法创建一个新的,非守护的线程,并且不包含特殊的配置信息。ThreadFactory 中只定义一个方法Thread newThread(Runnable r);,每当线程池需要创建一个新的线程时都会调用这个方法。
RejectedExecutionHandler : 当有界队列被填满同时线程池里的线程数达到maximumPoolSize后,饱和策略才会开始发挥作用。
线程池的运行过程
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
当一个任务被提交到线程池时,如果当前线程池中的线程数小于corePoolSize,则创建一个线程来处理该请求。即使其他工作线程处于空闲状态。如果当前线程池中的线程数大于corePoolSize同时小于maximumPoolSize时,则先将任务放入阻塞队列中,当在队列满的时候会创建新的线程。当线程池中的数量达到maximumPoolSize,队列满的时候。启动饱和策略来处理任务。
两种常用的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
该线程池将corePoolSize和maximumPoolSize设置为参数中指定的值,而且创建的线程不会超时。使用一个无界的LinkedBlockingQueue。如果所有的线程都处于忙碌状态,那么任务将在队列中等候。如果任务持续快速的到达,并且超过了线程池的处理速度,那么队列将会无限制的增加。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
该线程池将corePoolSize设置为0,maximumPoolSize设置为Integer.MAX_VALUE。超时时间为1分钟。使用SynchronousQueue来避免任务排队以及直接将任务从生产者移交给工作者线程。SynchronousQueue不是一个真正的队列,而是一种在线程之间进行移交的机制。要将任务放入SynchronousQueue中,必须有另外一个线程正在等待接收这个任务。当有线程空闲时间超过1分钟时则会被回收。
饱和策略:
AbortPolicy: 中止策略是默认的饱和策略,该饱和策略将抛出未检查的RejectExecutionException。调用者可以捕获这个异常,然后根据自己的需求编写自己的处理逻辑。
DiscardPolicy: 抛弃策略。当新的任务无法保存在队列中等待执行时,抛弃策略会悄悄抛弃该任务。
DiscardOldestPolicy: 抛弃最旧的策略。 当新的任务无法保存在队列中等待执行时,该策略会抛弃下一个将被执行的任务,然后重新提交新的任务。
CallerRunsPolicy: 调用者运行策略,该策略实现一种调节机制,既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新的任务流量。它不会在线程池的某个线程执行新提交的任务,而是在一个调用了execute时的主线程中执行。