diff --git a/pom.xml b/pom.xml
index bfc2d27e1e..1043680788 100644
--- a/pom.xml
+++ b/pom.xml
@@ -728,6 +728,7 @@
spring-static-resources
spring-swagger-codegen
+ spring-threads
spring-thymeleaf
spring-thymeleaf-2
diff --git a/spring-threads/pom.xml b/spring-threads/pom.xml
new file mode 100644
index 0000000000..4513c627b9
--- /dev/null
+++ b/spring-threads/pom.xml
@@ -0,0 +1,25 @@
+
+
+ 4.0.0
+ spring-threads
+ 0.0.1-SNAPSHOT
+ spring-threads
+ jar
+
+
+ com.baeldung
+ parent-spring-5
+ 0.0.1-SNAPSHOT
+ ../parent-spring-5
+
+
+
+
+ org.springframework
+ spring-context
+ ${spring.version}
+
+
+
+
diff --git a/spring-threads/src/test/java/com/baeldung/threading/ThreadPoolTaskExecutorUnitTest.java b/spring-threads/src/test/java/com/baeldung/threading/ThreadPoolTaskExecutorUnitTest.java
new file mode 100644
index 0000000000..0d927ebe69
--- /dev/null
+++ b/spring-threads/src/test/java/com/baeldung/threading/ThreadPoolTaskExecutorUnitTest.java
@@ -0,0 +1,98 @@
+package com.baeldung.threading;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+public class ThreadPoolTaskExecutorUnitTest {
+
+ 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();
+ }
+ });
+ }
+ }
+
+ @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());
+ }
+ }
+
+ @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());
+ }
+ }
+
+ @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());
+ }
+ }
+
+ @Test
+ public void whenCorePoolSizeFiveAndMaxPoolSizeTenAndQueueCapacityZero_thenTenThreads() {
+ ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
+ taskExecutor.setCorePoolSize(5);
+ taskExecutor.setMaxPoolSize(10);
+ taskExecutor.setQueueCapacity(0);
+ taskExecutor.afterPropertiesSet();
+
+ CountDownLatch countDownLatch = new CountDownLatch(10);
+ this.startThreads(taskExecutor, countDownLatch, 10);
+
+ while (countDownLatch.getCount() > 0) {
+ Assert.assertEquals(10, taskExecutor.getPoolSize());
+ }
+ }
+
+ @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());
+ }
+ }
+}