1. 概览

Spring中的 ThreadPoolTaskExecutor 是一个 JavaBean ,提供围绕java.util.concurrent.ThreadPoolExecutor 的抽象实例,并作为Spring 中org.springframework.core.task.TaskExecutor 暴露出来. 此外,它可以通过corePoolSize、maxPoolSize、queueCapacity、allowCoreThreadTimeOutkeepAliveSeconds的属性进行高度配置。在本教程中,我们将查看corePoolSizemaxPoolSize属性。

2. corePoolSize vs. maxPoolSize

刚接触到这种抽象的用户可能很容易混淆这两个配置属性的区别。因此,让我们分别看一下。

2.1. corePoolSize

corePoolSize 是在不超时情况下,保持活跃的最少线程数 。它是ThreadPoolTaskExecutor的一个可配置项。但是, ThreadPoolTaskExecutor* 抽象将该值的设置委托给底层的java.util.concurrent.ThreadPoolExecutor。为验证这一点,如果我们将allowCoreThreadTimeOut设置为true,那么所有线程都可能超时,等于将corePoolSize的值设置为零。

2.2. maxPoolSize

相反,maxPoolSize定义了可以创建的最大线程数。类似地,ThreadPoolTaskExecutormaxPoolSize属性也将其值委托给底层的java.util.concurrent.ThreadPoolExecutor。为验证这点, maxPoolSize依赖于queueCapacity,因为ThreadPoolTaskExecutor只会在其队列中的项目数超过queueCapacity*时创建一个新线程。

3. 所以,区别在哪?

corePoolSizemaxPoolSize之间的差别似乎很明显。然而,他们的行为有些微妙之处。

当我们向ThreadPoolTaskExecutor提交新任务时,如果正在运行的线程少于corePoolSize线程,即使池中有空闲线程,或者如果正在运行的线程少于maxPoolSize且由queueCapacity定义的队列已满,它也会创建一个新线程。

接下来,让我们看一些代码,以了解每个属性何时启动的示例。

4. 举例说明

首先,假设我们有一个执行新线程的方法,它来自名为startThreadsThreadPoolTaskExecutor

public void startThreads(ThreadPoolTaskExecutor taskExecutor, CountDownLatch countDownLatch,
  int numThreads) {
    for (int i = 0; i < numThreads; i++) {
        taskExecutor.execute(() -> {
            try {
                Thread.sleep(100L * ThreadLocalRandom.current().nextLong(1, 10));
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
    }
}

让我们测试ThreadPoolTaskExecutor的默认配置,它定义了一个线程的corePoolSize、一个无限制的maxPoolSize和无限制的queueCapacity。因此,我们希望无论启动多少任务,都只运行一个线程:

@Test
public void whenUsingDefaults_thenSingleThread() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.afterPropertiesSet();
 
    CountDownLatch countDownLatch = new CountDownLatch(10);
    this.startThreads(taskExecutor, countDownLatch, 10);
 
    while (countDownLatch.getCount() > 0) {
        Assert.assertEquals(1, taskExecutor.getPoolSize());
    }
}

现在,让我们将corePoolSize更改为最多5个线程,并确保它的行为与建议中的一样。因此,无论提交给ThreadPoolTaskExecutor的任务数是多少,我们都希望启动五个线程:

@Test
public void whenCorePoolSizeFive_thenFiveThreads() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(5);
    taskExecutor.afterPropertiesSet();
 
    CountDownLatch countDownLatch = new CountDownLatch(10);
    this.startThreads(taskExecutor, countDownLatch, 10);
 
    while (countDownLatch.getCount() > 0) {
        Assert.assertEquals(5, taskExecutor.getPoolSize());
    }
}

类似地,我们可以将maxPoolSize增加到10,而将corePoolSize保留为5。因此,我们希望只启动五个线程。为了更加清晰表明只有五个线程启动,因此queueCapacity仍然是无限制的:

@Test
public void whenCorePoolSizeFiveAndMaxPoolSizeTen_thenFiveThreads() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(5);
    taskExecutor.setMaxPoolSize(10);
    taskExecutor.afterPropertiesSet();
 
    CountDownLatch countDownLatch = new CountDownLatch(10);
    this.startThreads(taskExecutor, countDownLatch, 10);
 
    while (countDownLatch.getCount() > 0) {
        Assert.assertEquals(5, taskExecutor.getPoolSize());
    }
}

此外,我们现在将重复前面的测试,但将queueCapacity增加到10,并启动20个线程。因此,我们现在希望总共启动十个线程:

@Test
public void whenCorePoolSizeFiveAndMaxPoolSizeTenAndQueueCapacityTen_thenTenThreads() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(5);
    taskExecutor.setMaxPoolSize(10);
    taskExecutor.setQueueCapacity(10);
    taskExecutor.afterPropertiesSet();
 
    CountDownLatch countDownLatch = new CountDownLatch(20);
    this.startThreads(taskExecutor, countDownLatch, 20);
 
    while (countDownLatch.getCount() > 0) {
        Assert.assertEquals(10, taskExecutor.getPoolSize());
    }
}

同样,如果我们将queueCapactity设置为零并且只启动了10个任务,那么我们的ThreadPoolTaskExecutor中也会有10个线程。

5. 写在最后

ThreadPoolTaskExecutor是围绕java.util.concurrent.ThreadPoolExecutor的强大抽象,提供了配置corePoolSizemaxPoolSizequeueCapacity的选项。在本教程中,我们查看了corePoolSizemaxPoolSize属性,以及maxPoolSize如何与queueCapacity协同工作,从而使我们能够轻松地为任何用例创建线程池。

代码可在 Github 中找到!

叮叮叮!关注公众号: 锅外的大佬 ,加入锅外圈,不定时福利输出,hi欢迎你的加入哦

博客地址: http://www.developlee.top

ThreadPoolTaskExecutor 中 corePoolSize vs. maxPoolSize的更多相关文章

  1. corePoolSize和maxPoolSize的区别

    受限于硬件.内存和性能,我们不可能无限制的创建任意数量的线程,每一台机器允许的最大线程是一个有界值.因此ThreadPoolExecutor管理的线程数量是有界的.线程池就是用这些有限个数的线程,去执 ...

  2. Spring中的线程池和定时任务功能

    1.功能介绍 Spring框架提供了线程池和定时任务执行的抽象接口:TaskExecutor和TaskScheduler来支持异步执行任务和定时执行任务功能.同时使用框架自己定义的抽象接口来屏蔽掉底层 ...

  3. JAVA线程池学习,ThreadPoolTaskExecutor和ThreadPoolExecutor有何区别?

    初学者很容易看错,如果没有看到spring或者JUC源码的人肯定是不太了解的. ThreadPoolTaskExecutor是spring core包中的,而ThreadPoolExecutor是JD ...

  4. java 线程池(ExecutorService与Spring配置threadPoolTaskExecutor)

    一.java ExecutorService实现 创建ExecutorService变量private ExecutorService executor = null 2.执行对应任务时,首先生成线程 ...

  5. spring线程池ThreadPoolTaskExecutor与阻塞队列BlockingQueue

    一: ThreadPoolTaskExecutor是一个spring的线程池技术,查看代码可以看到这样一个字段: private ThreadPoolExecutor threadPoolExecut ...

  6. Java中使用ThreadPoolExecutor并行执行独立的单线程任务

    Java SE 5.0中引入了任务执行框架,这是简化多线程程序设计开发的一大进步.使用这个框架可以方便地管理任务:管理任务的生命周期以及执行策略. 在这篇文章中,我们通过一个简单的例子来展现这个框架所 ...

  7. Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)

    本文转载 https://www.javadoop.com 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c ...

  8. 深入理解NIO(二)—— Tomcat中对NIO的应用

    深入理解NIO(二)—— Tomcat中对NIO的应用 老哥行行好,转载和我说一声好吗,我不介意转载的,但是请把原文链接贴大点好吗 Tomcat大致架构 先贴两张图大致看一眼Tomcat的架构 Tom ...

  9. Java线程池实现原理及其在美团业务中的实践

    本文转载自Java线程池实现原理及其在美团业务中的实践 导语 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供 ...

随机推荐

  1. 利用Nginx或koa

    最近在做上传的图片的需求,思考上传之后的图片怎么访问的问题,因为后端是Node,一开始尝试写一个专门的接口通过传入图片的path来查找,试了一下感觉并不理想,因为要为每种类型的文件设置Content- ...

  2. SQL JOIN 和 UNION 用法

    1 SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons, Orders WHERE Persons.Id_P ...

  3. 改了改之前那个很糙的XXX

    将就着用X度去爬吧 <?php echo "***************************************\r\n"; echo "* SubDom ...

  4. 【转载】java 获取路径的各种方法

    转载只供个人学习参考,查看请前往原出处:http://www.cnblogs.com/guoyuqiangf8/p/3506768.html 主要方法有: (1).request.getRealPat ...

  5. Google Hacking --你真的会用Google吗?

    你真的会用Google吗?Google Hacking提升工作效率 阅读本文需要6.66分钟 Google hacking,也叫作google dorking.如果在 Google 上搜索 Googl ...

  6. 用RecyclerView做一个小清新的Gallery效果 - Ryan Lee的博客

    一.简介 RecyclerView现在已经是越来越强大,且不说已经被大家用到滚瓜烂熟的代替ListView的基础功能,现在RecyclerView还可以取代ViewPager实现Banner效果,当然 ...

  7. 通俗易懂DenseNet

    目录 写在前面 Dense Block与Transition Layer DenseNet网络架构与性能 理解DenseNet Plain Net.ResNet与DenseNet 参考 博客:博客园 ...

  8. SpringMVC 使用注解完成登录拦截

    目录 为了实现用户登录拦截你是否写过如下代码呢? 1. 基于Filter 2. 基于Struts 3. 基于SpringMVC 如何使用自定义注解完成自定义拦截呢? 登录注解 SpringMVC 拦截 ...

  9. angularV4+学习笔记

    angular学习笔记之组件篇 1注解 1.1组件注解 @Component注解,对组件进行配置. 1.1.1注解@Component的元数据 selector template/templateUr ...

  10. 【30分钟学完】canvas动画|游戏基础(4):边界与碰撞

    前言 本系列前几篇中常出现物体跑到画布外的情况,本篇就是为了解决这个问题. 阅读本篇前请先打好前面的基础. 本人能力有限,欢迎牛人共同讨论,批评指正. 越界检测 假定物体是个圆形,如图其圆心坐标即是物 ...