线程池参数详解


相关文章:
queue & Deque 详细解析
线程池参数

1. 线程池参数

构造函数:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {

任务提交,共有2种方法:

public void execute() //提交任务无返回值
public Future<?> submit() //任务执行完成后有返回值

参数解释:

  • corePoolSize
    线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。

    核心线程一旦创建,就不会再销毁

    • maximumPoolSize
      线程池中允许的最大线程数。如果当前阻塞队列满了(已到达corePoolSize上限后,后续任务会加入等待队列),且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于maximumPoolSize;

    注意:maximumPoolSize=corePoolSize+非核心线程数;假设非核心数是>0的,一旦提交的任务数>corePoolSize,该任务就会被放入阻塞队列中,而不是立即启动一个非核心线程。那么非核心线程是什么时候起的呢?

  • keepAliveTime
    线程池维护线程所允许的空闲时间。当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime;

    仅对非核心线程而言

  • unit
    keepAliveTime的单位;

  • workQueue
    用来保存等待被执行的任务的阻塞队列,且任务必须实现Runable接口,在JDK中提供
    了如下阻塞队列:

    • 1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
    • 2、LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene;
    • 3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene;
    • 4、priorityBlockingQuene:具有优先级的无界阻塞队列;

    构造函数中参数是 BlockingQueue接口,必须是阻塞的

  • threadFactory
    它是ThreadFactory类型的变量,用来创建新线程。默认使用Executors.defaultThreadFactory() 来创建线程。使用默认的ThreadFactory来创建线程时,会使新创建的线程具有相同的NORM_PRIORITY优先级并且是非守护线程,同时也设置了线程的名称。

  • handler
    线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:

    • 1、AbortPolicy:直接抛出异常,默认策略;
    • 2、CallerRunsPolicy:用调用者所在的线程来执行任务;
    • 3、DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
    • 4、DiscardPolicy:直接丢弃任务;

上面的4种策略都是ThreadPoolExecutor的内部类。

当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。

2. 队列

构造函数中参数是 BlockingQueue接口,必须是阻塞的,但是不限制是否有有界。

队列有有界队列和无界队列之分,因此,此时可选队列是:

  • 有界阻塞
  • 无界阻塞 不建议使用,会导致内存溢出,此时队列永远不会满,handler线程池的饱和策略也无法生效。

在这里插入图片描述

2.1 为什么是先添加队列而不是先创建最大线程?

就好比一个企业里面有十个(core)正式工的名额,最多招十个正式工(核心线程),要是任务超过正式人数(task>core)的情况下,工厂领导(线程池)不是首先扩招工人,还是这十个人,但是任务可以稍积压一下。即先放到队列中去(代价低)。十个正式工慢慢干,迟早会干完的,如果任务还在持续增加,超过正式工的加班忍耐极限了(队列满了),就招外包(非核心线程)帮忙了,还是正式工加外包还不能完成任务,那么新来的任务就会被领导拒绝(线程池拒绝策略)。

核心思想是尽量少新增线程或回收线程,如果不先放入队列,就会频繁的进行回收和新增操作,耗费cpu资源。试想临时招工人再辞退,再招再辞退,成本太大。

除了新增或回收线程会耗费资源外,在创建新线程的时候,是要获取全局锁的,这个时候其它的就得阻塞,影响了整体效率。

2.2 线程池中阻塞队列的作用?

  • 首先需要队列,是为了削峰。

    如果是有界的队列的话,总会满,而我们的机制是满了之后,才会开启新的额外线程。那么等待线程开启的时段内,任务是不能丢弃的。

    一般的队列只能保证作为一个有限长度的缓冲区,如果超出了缓冲长度,就无法保留当前的任务了,会直接丢弃,因此需要阻塞队列通过阻塞保留住当前想要继续入队的任务。

  • 其次,阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源。阻塞队列自带阻塞和唤醒功能,不需要做额外处理,无任务执行时,线程池利用阻塞队列的take方法挂起,从而维持核心线程的存活,不至于一直占用CPU资源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java线程池是一种用于管理和复用线程的机制,它可以提高多线程程序的性能和效率。在Java中,线程池由ThreadPoolExecutor类实现,通过设置不同的参数可以对线程池的行为进行调整。 以下是Java线程池的一些常用参数及其解释: 1. corePoolSize(核心线程数):线程池中始终保持的活动线程数,即使它们处于空闲状态。当有新任务提交时,如果活动线程数小于corePoolSize,则会创建新线程来处理任务。 2. maximumPoolSize(最大线程数):线程池中允许存在的最大线程数。当活动线程数达到maximumPoolSize并且工作队列已满时,新任务将会被拒绝。 3. keepAliveTime(线程空闲时间):当线程池中的线程数量超过corePoolSize时,多余的空闲线程在等待新任务到来时的最长等待时间。超过这个时间,空闲线程将被终止。 4. unit(时间单位):keepAliveTime的时间单位,可以是秒、毫秒、微秒等。 5. workQueue(工作队列):用于存储等待执行的任务的阻塞队列。常见的工作队列有ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue等。 6. threadFactory(线程工厂):用于创建新线程的工厂类。可以自定义线程的名称、优先级等属性。 7. handler(拒绝策略):当线程池无法接受新任务时的处理策略。常见的拒绝策略有AbortPolicy(默认,抛出RejectedExecutionException异常)、CallerRunsPolicy(由调用线程执行任务)、DiscardPolicy(直接丢弃任务)和DiscardOldestPolicy(丢弃最旧的任务)。 这些参数可以根据实际需求进行调整,以达到最佳的线程池性能和资源利用率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值