JDK并发包中的线程池(二)核心线程池的内部实现

来源:互联网 发布:selenium java client 编辑:程序博客网 时间:2024/06/11 11:52

对于核心的几个线程池

newSingleThreadExecutornewFixedThreadPoolnewCachedThreadPool

其内部都是使用的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) {        }}
原创粉丝点击