ThreadPoolExecutor

java.lang.Object
java.util.concurrent.AbstractExecutorService
java.util.concurrent.ThreadPoolExecutor
所 有已实现的接口:
ExecutorExecutorService

强烈建议程序员使用较为方便的 Executors 工厂方法 Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)和 Executors.newSingleThreadExecutor()(单个后台线程),它们均为大多数使用场景预定义了设置。下面是对ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory, 

RejectedExecutionHandler handler) 的一些分析:

  1. 核心和最大池大小:ThreadPoolExecutor将根据corePoolSize和maximumPoolSize设置的边界自动调整大小。当新任务在方法execute(java.lang.Runnable) 中提交时,如果运行的线程少于 corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则仅当队列满时才创建新线程。如果设置的 corePoolSize 和 maximumPoolSize 相同,则创建了固定大小的线程池。如果将 maximumPoolSize 设置为基本的无界值(如 Integer.MAX_VALUE),则允许池适应任意数量的并发任务。
  2.  创建新线程:使用 ThreadFactory 创建新线程。如果没有另外说明,则在同一个 ThreadGroup 中一律使用 Executors.defaultThreadFactory() 创建线程,并且这些线程具有相同的NORM_PRIORITY 优先级和非守护进程状态。通过提供不同的 ThreadFactory,可以改变线程的名称、线程组、优先级、守护进程状态,等等。如果从 newThread 返回 null 时ThreadFactory 未能创建线程,则执行程序将继续运行,但不能执行任何任务。
  3. 保持活动时间如果池中当前有多于 corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止
  4. 排队所有 BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互:

    • 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。
    • 如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。
    • 如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。
  5. 排队有三种通用策略:
    1. 直接提交。工作队列的默认选项是 SynchronousQueue(一种阻塞队列,其中每个 put 必须等待一个 take,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有),它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程此策略可以避免在处理可能具有内部依赖性的请求集合时出现锁定直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。
    2. 无界队列使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue一个基于已链接节点的、范围任意的 blocking queue)将导致在所有 corePoolSize 线程都忙的情况下将新任务加入队列。这样,创建的线程就不会超过 corePoolSize,maximumPoolSize 的值也就无效了当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列,例如,在 Web 页服务器中。
    3. 有界队列当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序)有助于防止资源耗尽,但是可能较难调整和控制队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。
  6. 此类提供 protected 可重写的 beforeExecute(java.lang.Thread, java.lang.Runnable)  afterExecute(java.lang.Runnable, java.lang.Throwable) 方法,这两种方法分别在执行每个任务之前和之后调用。如果挂钩或回调方法抛出异常,则内部辅助线程将依次失败并突然终止。

posted on 2010-03-15 17:29  北冥有鱼,化而为鸟  阅读(1965)  评论(0编辑  收藏  举报

导航