diff --git a/spring-threads/.gitignore b/spring-threads/.gitignore new file mode 100644 index 0000000000..08259abdaf --- /dev/null +++ b/spring-threads/.gitignore @@ -0,0 +1,12 @@ +RemoteSystemsTempFiles/ +.classpath +.project +.settings/ +bin/ +.metadata/ +docs/*.autosave +.recommenders/ +build/ +.gradle/ +.DS_Store +.idea/ \ No newline at end of file diff --git a/spring-threads/README.md b/spring-threads/README.md new file mode 100644 index 0000000000..7f4ee1d6a1 --- /dev/null +++ b/spring-threads/README.md @@ -0,0 +1,10 @@ +## Spring Threads + +This module contains articles about threading using threads, specifically Spring's ThreadPoolTaskExecutor + +### Relevant Articles: +- [Introduction to Thread Pools in Java](https://www.baeldung.com/thread-pool-java-and-guava) +- [How To Do @Async in Spring](https://www.baeldung.com/spring-async) +- [A Guide to the Spring Task Scheduler](https://www.baeldung.com/spring-task-scheduler) +- [A Guide to the Java ExecutorService](https://www.baeldung.com/java-executor-service-tutorial) + diff --git a/spring-threads/pom.xml b/spring-threads/pom.xml new file mode 100644 index 0000000000..bf3d460ac0 --- /dev/null +++ b/spring-threads/pom.xml @@ -0,0 +1,29 @@ + + + 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} + + + + + 3.12.2 + + + 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..196f67a08f --- /dev/null +++ b/spring-threads/src/test/java/com/baeldung/threading/ThreadPoolTaskExecutorUnitTest.java @@ -0,0 +1,130 @@ +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 { + + @Test + public void whenUsingDefaults_thenSingleThread() { + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.afterPropertiesSet(); + + CountDownLatch countDownLatch = new CountDownLatch(10); + for (int i = 0; i < 10; i++) { + taskExecutor.execute(() -> { + try { + Thread.sleep(10L * ThreadLocalRandom.current().nextLong(1, 10)); + countDownLatch.countDown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + } + + 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); + for (int i = 0; i < 10; i++) { + taskExecutor.execute(() -> { + try { + Thread.sleep(100L * ThreadLocalRandom.current().nextLong(1, 10)); + countDownLatch.countDown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + } + + while (countDownLatch.getCount() > 0) { + Assert.assertEquals(5, taskExecutor.getPoolSize()); + } + } + + @Test + public void whenCorePoolSizeFive_andMaxPoolSizeTen_thenFiveThreads() { + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setCorePoolSize(5); + taskExecutor.setMaxPoolSize(10); + taskExecutor.afterPropertiesSet(); + + CountDownLatch countDownLatch = new CountDownLatch(10); + for (int i = 0; i < 10; i++) { + taskExecutor.execute(() -> { + try { + Thread.sleep(100L * ThreadLocalRandom.current().nextLong(1, 10)); + countDownLatch.countDown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + } + + while (countDownLatch.getCount() > 0) { + Assert.assertEquals(5, taskExecutor.getPoolSize()); + } + } + + @Test + public void whenCorePoolSizeFive_andMaxPoolSizeTen_andQueueCapacityZero_thenTenThreads() { + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setCorePoolSize(5); + taskExecutor.setMaxPoolSize(10); + taskExecutor.setQueueCapacity(0); + taskExecutor.afterPropertiesSet(); + + CountDownLatch countDownLatch = new CountDownLatch(10); + for (int i = 0; i < 10; i++) { + taskExecutor.execute(() -> { + try { + Thread.sleep(100L * ThreadLocalRandom.current().nextLong(1, 10)); + countDownLatch.countDown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + } + + while (countDownLatch.getCount() > 0) { + Assert.assertEquals(10, taskExecutor.getPoolSize()); + } + } + + @Test + public void whenCorePoolSizeFive_andMaxPoolSizeTen_andQueueCapacityTen_thenTenThreads() { + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setCorePoolSize(5); + taskExecutor.setMaxPoolSize(10); + taskExecutor.setQueueCapacity(10); + taskExecutor.afterPropertiesSet(); + + CountDownLatch countDownLatch = new CountDownLatch(10); + for (int i = 0; i < 20; i++) { + taskExecutor.execute(() -> { + try { + Thread.sleep(100L * ThreadLocalRandom.current().nextLong(1, 10)); + countDownLatch.countDown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + } + + while (countDownLatch.getCount() > 0) { + Assert.assertEquals(10, taskExecutor.getPoolSize()); + } + } +}