1. 概览
Spring中的 ThreadPoolTaskExecutor 是一个 JavaBean ,提供围绕 java.util.concurrent.ThreadPoolExecutor 的抽象实例,并作为Spring 中 org.springframework.core.task.TaskExecutor 暴露出来. 此外,它可以通过 corePoolSize、maxPoolSize、queueCapacity、allowCoreThreadTimeOut 和 keepAliveSeconds 的属性进行高度配置。在本教程中,我们将查看 corePoolSize 和 maxPoolSize 属性。
刚接触到这种抽象的用户可能很容易混淆这两个配置属性的区别。因此,让我们分别看一下。
corePoolSize 是在不超时情况下,保持活跃的最少线程数。它是 ThreadPoolTaskExecutor 的一个可配置项。但是, ThreadPoolTaskExecutor* 抽象将该值的设置委托给底层的 java.util.concurrent.ThreadPoolExecutor 。为验证这一点,如果我们将 allowCoreThreadTimeOut 设置为 true ,那么所有线程都可能超时,等于将 corePoolSize 的值设置为零。
相反, maxPoolSize定义了可以创建的最大线程数 。类似地, ThreadPoolTaskExecutor 的 maxPoolSize 属性也将其值委托给底层的 java.util.concurrent.ThreadPoolExecutor 。为验证这点, maxPoolSize 依赖于queueCapacity,因为 ThreadPoolTaskExecutor 只会在其队列中的项目数超过 queueCapacity*时创建一个新线程。
corePoolSize 和 maxPoolSize 之间的差别似乎很明显。然而,他们的行为有些微妙之处。
当我们向 ThreadPoolTaskExecutor提交新任务时, 如果正在运行的线程少于 corePoolSize 线程,即使池中有空闲线程,或者如果正在运行的线程少于 maxPoolSize 且由 queueCapacity 定义的队列已满,它也会创建一个新线程。
接下来,让我们看一些代码,以了解每个属性何时启动的示例。
首先,假设我们有一个执行新线程的方法,它来自名为 startThreads 的 ThreadPoolTaskExecutor :
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个线程。
ThreadPoolTaskExecutor 是围绕 java.util.concurrent.ThreadPoolExecutor 的强大抽象,提供了配置 corePoolSize 、 maxPoolSize 和 queueCapacity 的选项。在本教程中,我们查看了 corePoolSize 和 maxPoolSize 属性,以及 maxPoolSize 如何与 queueCapacity 协同工作,从而使我们能够轻松地为任何用例创建线程池。
代码可在 Github 中找到!
最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!
• 001:《Java并发与高并发解决方案》学习笔记; • 002:《深入JVM内核——原理、诊断与优化》学习笔记; • 003:《Java面试宝典》 • 004:《Docker开源书》 • 005:《Kubernetes开源书》 • 006:《DDD速成(领域驱动设计速成)》 • 007: 全部 • 008: 加技术讨论群
想知道更多?长按/扫码关注我吧↓↓↓ >>>技术讨论群<<< 喜欢就点个 "在看" 呗^_^