ThreadPoolExecutor参数设置
您目前处于:技术核心竞争力  2014-10-10

ThreadPoolExecutor的完整构造方法的签名是:

ThreadPoolExecutor( 
                    int corePoolSize, // 线程池维护线程的最少数量
                    int maximumPoolSize, // 线程池维护线程的最大数量 
                    long keepAliveTime, // 线程池维护线程所允许的空闲时间 
                    TimeUnit unit, // 线程池维护线程所允许的空闲时间的单位 
                    BlockingQueue<Runnable> workQueue, // 线程池所使用的缓冲队列  
                    ThreadFactory threadFactory, RejectedExecutionHandler handler // 线程池对拒绝任务的处理策略 
                )

线程池的工作过程

1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

2. 当调用 execute() 方法添加一个任务时,线程池会做如下判断:

a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;
d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常。

3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。

4. 当一个线程空闲,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

ThreadPoolExecutor是Executors类的底层实现

在JDK帮助文档中,有如此一段话:

强烈建议程序员使用较为方便的 Executors 工厂方法 Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)和 Executors.newSingleThreadExecutor()(单个后台线程),它们均为大多数使用场景预定义了设置。

  • ExecutorService newFixedThreadPool(int nThreads):固定大小线程池

  •     public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
  • ExecutorService newSingleThreadExecutor():单线程

  •     public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
        }
  • ExecutorService newCachedThreadPool():无界线程池,可以进行自动线程回收

  •     public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }

    BlockingQueue

  • 1. SynchronousQueue

  • 一种阻塞队列,其中每个 put 必须等待一个 take,反之亦然,即其的操作必须是放和取交替完成的。同步队列没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,因为仅在试图要取得元素时,该元素才存在;除非另一个线程试图移除某个元素,否则也不能(使用任何方法)添加元素;也不能迭代队列,因为其中没有元素可用于迭代。队列的头是尝试添加到队列中的首个已排队线程元素;如果没有已排队线程,则不添加元素并且头为 null。对于其他Collection 方法,SynchronousQueue 作为一个空集合。此队列不允许 null 元素。

  • 2. LinkedBlockingQueue

  • 一个基于链表的、范围任意的 blocking queue。此队列按 FIFO(先进先出)排序元素。队列的头部是在队列中时间最长的元素。队列的尾部是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。

  • 3. ArrayBlockingQueue

  • ArrayBlockingQueue是一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部是在队列中存在时间最长的元素。队列的尾部是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列检索操作则是从队列头部开始获得元素。

    这是一个典型的"有界缓存区",固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致放入操作受阻塞;试图从空队列中检索元素将导致类似阻塞。

  • 4. PriorityBlockingQueue

  • 一个无界的阻塞队列,它使用与类 PriorityQueue 相同的顺序规则,并且提供了阻塞检索的操作。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会失败(导致 OutOfMemoryError)。此类不允许使用 null 元素。依赖自然顺序的优先级队列也不允许插入不可比较的对象。

  • 5. DelayQueue

  • Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且 poll 将返回 null。当一个元素的getDelay(TimeUnit.NANOSECONDS)方法返回一个小于或等于零的值时,则出现期满。此队列不允许使用 null 元素。

  • 6. BlockingDque + LinkedBlockingQueue

  • BlockingDque为阻塞双端队列接口,实现类有LinkedBlockingDque。双端队列特别之处是它首尾都可以操作。LinkedBlockingDque不同于LinkedBlockingQueue,它只用一个lock来维护读写操作,并由这个lock实例化出两个Condition notEmpty及notFull,而LinkedBlockingQueue读和写分别维护一个lock。

    RejectedExecutionHandler

    RejectedExecutionHandler接口提供了对于拒绝任务的处理的自定方法的机制。在ThreadPoolExecutor中已经默认包含了4中策略:

  • CallerRunsPolicy

  • 线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                if (!e.isShutdown()) {
                    r.run();
                }
            }
  • AbortPolicy

  • 处理程序遭到拒绝将抛出运行时 RejectedExecutionException。

            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                throw new RejectedExecutionException();
            }
  • DiscardPolicy

  • 不能执行的任务将被删除。

            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            }
  • DiscardOldestPolicy

  • 如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序

            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                if (!e.isShutdown()) {
                    e.getQueue().poll();
                    e.execute(r);
                }
            }

转载请并标注: “本文转载自 linkedkeeper.com ”  ©著作权归作者所有