ThreadPoolExecutor 详解

目录

概述

FixedThreadPool 详解

SingleThreadExecutor 详解

CachedThreadPool 详解


概述

        Executor 框架最核心的类是 ThreadPoolExecutor,它是线程池的实现类,主要由下列 4 个组件构成。

  •  corePool:核心线程池的大小。
  •  maximumPool:最大线程池的大小。
  •  BlockingQueue:用来暂时保存任务的工作队列。
  •  RejectedExecutionHandler:当 ThreadPoolExecutor 已经关闭或 ThreadPoolExecutor 已经饱和时(达到了最大线程池大小且工作队列已满),execute()方法将要调用的 Handler。

通过 Executor 框架的工具类 Executors,可以创建 3 种类型的 ThreadPoolExecutor。

• FixedThreadPool   • SingleThreadExecutor。 • CachedThreadPool 

FixedThreadPool 详解

FixedThreadPool 被称为可重用固定线程数的线程池。

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

         FixedThreadPool 的 corePoolSize 和 maximumPoolSize 都被设置为创建 FixedThreadPool 时指定的参数 nThreads。

        当线程池中的线程数大于 corePoolSize 时,keepAliveTime 为多余的空闲线程等待新任务的最长时间,超过这个时间后多余的线程将被终止。这里把 keepAliveTime 设置为 0L,意味着多余的空闲线程会被立即终止。

1) 如果当前运行的线程数少于 corePoolSize,则创建新线程来执行任务。

2) 在线程池完成预热之后(当前运行的线程数等于 corePoolSize),将任务加入 LinkedBlockingQueue。

3) 线程执行完 1 中的任务后,会在循环中反复从 LinkedBlockingQueue 获取任务来 执行。

4) FixedThreadPool 使用无界队列 LinkedBlockingQueue 作为线程池的工作队列(队列的容量为 Integer.MAX_VALUE)。使用无界队列作为工作队列会对线程池带来如下影响。 1)当线程池中的线程数达到 corePoolSize 后,新任务将在无界队列 中等待,因此线程池中的线程数不会超过 corePoolSize。

由于 1,使用无界队列时 maximumPoolSize 将是一个无效参数。

由于 1 和 2,使用无界队列时 keepAliveTime 将是一个无效参数。

由于使用无界队列,运行中的 FixedThreadPool(未执行方法 shutdown()或 shutdownNow())不会拒绝任务(不会调用 RejectedExecutionHandler.rejectedExecution 方法)。

SingleThreadExecutor 详解

SingleThreadExecutor 是使用单个 worker 线程的 Executor。

public static ExecutorService newSingleThreadExecutor() {
     return new FinalizableDelegatedExecutorService(
             new ThreadPoolExecutor(
                    1, 
                    1, 
                    0L, 
                    TimeUnit.MILLISECONDS, 
                    new LinkedBlockingQueue<Runnable>()
             )
         );
}

SingleThreadExecutor 的 corePoolSize 和 maximumPoolSize 被设置为1。其他参数与 FixedThreadPool 相同。

SingleThreadExecutor 使用无界队列 LinkedBlockingQueue 作为线程池的工作队列(队列的容量为 Integer.MAX_VALUE)。SingleThreadExecutor 使用无界队列作为工作队列对线程池带来的影响与 FixedThreadPool 相同。

1) 如果当前运行的线程数少于 corePoolSize(即线程池中无运行的线程),则创建一个新线程来执行任务。

2) 在线程池完成预热之后(当前线程池中有一个运行的线程),将任务加入 LinkedBlockingQueue。

3) 线程执行完 1 中的任务后,会在一个无限循环中反复从 LinkedBlockingQueue 获取任务来执行。

CachedThreadPool 详解

 CachedThreadPool 是一个会根据需要创建新线程的线程池。

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

        CachedThreadPool 的 corePoolSize 被设置为 0,即 corePool 为空;maximumPoolSize 被设置为 Integer.MAX_VALUE,即 maximumPool 是无界的。这里把 keepAliveTime 设置为 60L,意味着 CachedThreadPool 中的空闲线程等待新任务的最长时间为 60 秒,空闲线程超过 60 秒后将会被终止。

        FixedThreadPool 和 SingleThreadExecutor 使用无界队列 LinkedBlockingQueue 作为线程池的工作队列。

        CachedThreadPool 使用没有容量的 SynchronousQueue 作为线程池的工作队列,但 CachedThreadPool 的 maximumPool 是无界的。

        这意味着,如果主线程提交任务的速度高于 maximumPool 中线程处理任务的速度时,CachedThreadPool 会不断创建新线程。极端情况下, CachedThreadPool 会因为创建过多线程而耗尽 CPU 和内存资源。

1) 首先执行 SynchronousQueue.offer(Runnable task)。如果当前 maximumPool 中有空闲线程正在执行 SynchronousQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS),那么主线程执行 offer 操作与空闲线程执行的 poll 操作配对成功,主线程把任务交给空闲线程执行,execute()方法执行完成;否则执行下面的步骤 2)。

2) 当初始 maximumPool 为空,或者 maximumPool 中当前没有空闲线程时,将没有线程执行 SynchronousQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)。这种情况下,步骤 1)将失败。此时 CachedThreadPool 会创建一个新线程执行任务,execute()方法执行完成。

3) 在步骤 2)中新创建的线程将任务执行完后,会执行 SynchronousQueue.poll (keepAliveTime,TimeUnit.NANOSECONDS)。这个 poll 操作会让空闲线程最多在 SynchronousQueue 中等待 60 秒钟。如果 60 秒钟内主线程提交了一个新任务(主线程执行步骤 1)),那么这个空闲线程将执行主线程提交的新任务;否则,这个空闲线程将终止。由于空闲 60 秒的空闲线程会被终止,因此长时间保持空闲的 CachedThreadPool 不会使用任何资源。 

        SynchronousQueue 是一个没有容量的阻塞队列。每个插入操作必须等 待另一个线程的对应移除操作,反之亦然。CachedThreadPool 使用 SynchronousQueue, 把主线程提交的任务传递给空闲线程执行。

CachedThreadPool 的任务传递示意图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadPoolExecutorJava 提供的用于创建线程池的类,它的构造函数有很多参数,下面是对这些参数的详细解释: 1. corePoolSize:线程池中核心线程的数量。当线程池中的线程数量小于 corePoolSize 时,新的任务会一直创建新的线程直到达到 corePoolSize 个线程。 2. maximumPoolSize:线程池中最大线程数。当线程池中的线程数量达到 corePoolSize 后,新的任务会被放入到等待队列中,等待被执行。如果等待队列已满,且线程池中的线程数量小于 maximumPoolSize,则会创建新的线程执行任务。 3. keepAliveTime:线程池中非核心线程的超时时间。当线程池中的线程数量大于 corePoolSize 时,多余的线程会被回收,但回收前会等待 keepAliveTime 时间,如果在这个时间内没有新的任务需要执行,则这个线程会被终止。 4. TimeUnit:超时时间的单位。 5. workQueue:用于缓存等待执行的任务的队列。ThreadPoolExecutor 提供了多种队列,如 ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue 等。可以根据需求选择不同的队列。 6. threadFactory:用于创建新的线程。ThreadPoolExecutor 默认使用 Executors.defaultThreadFactory() 创建线程。如果需要自定义线程创建方式,可以实现 ThreadFactory 接口。 7. handler:线程池中的线程数量达到 maximumPoolSize,并且等待队列已满时,新的任务的处理策略。ThreadPoolExecutor 提供了 4 种策略: - AbortPolicy:直接抛出异常; - CallerRunsPolicy:不在新线程中执行任务,而是让调用 execute 方法的线程执行任务; - DiscardOldestPolicy:丢弃最老的任务,执行当前任务; - DiscardPolicy:直接丢弃任务。 这些参数可以根据实际需求进行调整,以达到最优的线程池效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值