• ThreadPoolTaskExecutor 中 corePoolSize vs. maxPoolSize


    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

  • 相关阅读:
    React Native组件左右两端展示(flex:1、justifyContent:'space-between')
    iOS 蓝牙开发详解(基本知识、相关类图、交互流程)
    iOS 蓝牙开发 Mac地址问题
    AFNetwork监听网络失效
    查看linux系统版本和cpu
    docker常用命令
    docker 常用命令--镜像删除
    docker部署nginx
    常见数据库会话查询脚本
    DB性能瓶颈分析思路
  • 原文地址:https://www.cnblogs.com/liululee/p/12596473.html
Copyright © 2020-2023  润新知