diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java index 2f0796b491..16d9aa4c9f 100644 --- a/core-java-concurrency/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/executorservice/DelayedCallable.java @@ -1,11 +1,18 @@ package com.baeldung.concurrent.executorservice; import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; public class DelayedCallable implements Callable { private String name; private long period; + private CountDownLatch latch; + + public DelayedCallable(String name, long period, CountDownLatch latch) { + this(name, period); + this.latch = latch; + } public DelayedCallable(String name, long period) { this.name = name; @@ -16,9 +23,15 @@ public class DelayedCallable implements Callable { try { Thread.sleep(period); + + if (latch != null) { + latch.countDown(); + } + } catch (InterruptedException ex) { // handle exception ex.printStackTrace(); + Thread.currentThread().interrupt(); } return name; diff --git a/core-java-concurrency/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishTest.java b/core-java-concurrency/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishTest.java index 0f461909ea..17b71aa35b 100644 --- a/core-java-concurrency/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishTest.java +++ b/core-java-concurrency/src/test/java/com/baeldung/concurrent/executorservice/WaitingForThreadsToFinishTest.java @@ -9,22 +9,91 @@ import java.util.List; import java.util.concurrent.*; import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.fail; public class WaitingForThreadsToFinishTest { private static final Logger LOG = LoggerFactory.getLogger(WaitingForThreadsToFinishTest.class); private final static ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); + public void awaitTerminationAfterShutdown(ExecutorService threadPool) { + threadPool.shutdown(); + try { + if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) { + threadPool.shutdownNow(); + } + } catch (InterruptedException ex) { + threadPool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + @Test + public void givenMultipleThreads_whenUsingCountDownLatch_thenMainShoudWaitForAllToFinish() { + + ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); + + try { + long startTime = System.currentTimeMillis(); + + // create a CountDownLatch that waits for the 2 threads to finish + CountDownLatch latch = new CountDownLatch(2); + + for (int i = 0; i < 2; i++) { + WORKER_THREAD_POOL.submit(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + latch.countDown(); + } catch (InterruptedException e) { + e.printStackTrace(); + Thread.currentThread().interrupt(); + } + } + }); + } + + // wait for the latch to be decremented by the two threads + latch.await(); + + long processingTime = System.currentTimeMillis() - startTime; + assertTrue(processingTime >= 1000); + + } catch (InterruptedException e) { + e.printStackTrace(); + } + + awaitTerminationAfterShutdown(WORKER_THREAD_POOL); + } + @Test public void givenMultipleThreads_whenInvokeAll_thenMainThreadShouldWaitForAllToFinish() { ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10); - List> callables = Arrays.asList(new DelayedCallable("fast thread", 100), new DelayedCallable("slow thread", 3000)); - + List> callables = Arrays.asList( + new DelayedCallable("fast thread", 100), + new DelayedCallable("slow thread", 3000)); + try { long startProcessingTime = System.currentTimeMillis(); List> futures = WORKER_THREAD_POOL.invokeAll(callables); + + awaitTerminationAfterShutdown(WORKER_THREAD_POOL); + + try { + WORKER_THREAD_POOL.submit(new Callable() { + @Override + public String call() throws Exception { + fail("This thread should have been rejected !"); + Thread.sleep(1000000); + return null; + } + }); + } catch (RejectedExecutionException ex) { + // + } long totalProcessingTime = System.currentTimeMillis() - startProcessingTime; assertTrue(totalProcessingTime >= 3000); @@ -39,9 +108,7 @@ public class WaitingForThreadsToFinishTest { } catch (ExecutionException | InterruptedException ex) { ex.printStackTrace(); - } - - WORKER_THREAD_POOL.shutdown(); + } } @Test @@ -49,14 +116,14 @@ public class WaitingForThreadsToFinishTest { CompletionService service = new ExecutorCompletionService<>(WORKER_THREAD_POOL); - List> callables = Arrays.asList(new DelayedCallable("fast thread", 100), new DelayedCallable("slow thread", 3000)); + List> callables = Arrays.asList( + new DelayedCallable("fast thread", 100), + new DelayedCallable("slow thread", 3000)); for (Callable callable : callables) { service.submit(callable); } - WORKER_THREAD_POOL.shutdown(); - try { long startProcessingTime = System.currentTimeMillis(); @@ -79,8 +146,9 @@ public class WaitingForThreadsToFinishTest { } catch (ExecutionException | InterruptedException ex) { ex.printStackTrace(); + } finally { + awaitTerminationAfterShutdown(WORKER_THREAD_POOL); } - } @Test @@ -142,6 +210,6 @@ public class WaitingForThreadsToFinishTest { e.printStackTrace(); } - WORKER_THREAD_POOL.shutdown(); + awaitTerminationAfterShutdown(WORKER_THREAD_POOL); } } diff --git a/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleFormatter.java b/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleFormatter.java new file mode 100644 index 0000000000..069e9df084 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleFormatter.java @@ -0,0 +1,16 @@ +package com.baeldung.dependencyinjectiontypes; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class ArticleFormatter { + + @SuppressWarnings("resource") + public static void main(String[] args) { + ApplicationContext context = new ClassPathXmlApplicationContext("dependencyinjectiontypes-context.xml"); + ArticleWithSetterInjection article = (ArticleWithSetterInjection) context.getBean("articleWithSetterInjectionBean"); + String formattedArticle = article.format("This is a text !"); + + System.out.print(formattedArticle); + } +} diff --git a/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleWithConstructorInjection.java b/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleWithConstructorInjection.java new file mode 100644 index 0000000000..776e9f4040 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleWithConstructorInjection.java @@ -0,0 +1,17 @@ +package com.baeldung.dependencyinjectiontypes; + +import org.springframework.beans.factory.annotation.Autowired; + +public class ArticleWithConstructorInjection { + + private TextFormatter formatter; + + @Autowired + public ArticleWithConstructorInjection(TextFormatter formatter) { + this.formatter = formatter; + } + + public String format(String text) { + return formatter.format(text); + } +} diff --git a/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleWithSetterInjection.java b/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleWithSetterInjection.java new file mode 100644 index 0000000000..931c6ea276 --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/ArticleWithSetterInjection.java @@ -0,0 +1,21 @@ +package com.baeldung.dependencyinjectiontypes; + +import org.springframework.beans.factory.annotation.Autowired; + +public class ArticleWithSetterInjection { + + private TextFormatter formatter; + + public ArticleWithSetterInjection(TextFormatter formatter) { + this.formatter = formatter; + } + + @Autowired + public void setTextFormatter(TextFormatter formatter) { + this.formatter = formatter; + } + + public String format(String text) { + return formatter.format(text); + } +} diff --git a/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/TextFormatter.java b/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/TextFormatter.java new file mode 100644 index 0000000000..204436c9bd --- /dev/null +++ b/spring-core/src/main/java/com/baeldung/dependencyinjectiontypes/TextFormatter.java @@ -0,0 +1,8 @@ +package com.baeldung.dependencyinjectiontypes; + +public class TextFormatter { + + public String format(String text) { + return text.toUpperCase(); + } +} diff --git a/spring-core/src/main/resources/dependencyinjectiontypes-context.xml b/spring-core/src/main/resources/dependencyinjectiontypes-context.xml new file mode 100644 index 0000000000..bd6b3c408d --- /dev/null +++ b/spring-core/src/main/resources/dependencyinjectiontypes-context.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-core/src/test/java/com/baeldung/dependencyinjectiontypes/DependencyInjectionTest.java b/spring-core/src/test/java/com/baeldung/dependencyinjectiontypes/DependencyInjectionTest.java new file mode 100644 index 0000000000..57c1927e58 --- /dev/null +++ b/spring-core/src/test/java/com/baeldung/dependencyinjectiontypes/DependencyInjectionTest.java @@ -0,0 +1,35 @@ +package com.baeldung.dependencyinjectiontypes; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class DependencyInjectionTest { + + @Test + public void givenAutowiredAnnotation_WhenSetOnSetter_ThenDependencyValid() { + + ApplicationContext context = new ClassPathXmlApplicationContext("dependencyinjectiontypes-context.xml"); + ArticleWithSetterInjection article = (ArticleWithSetterInjection) context.getBean("articleWithSetterInjectionBean"); + + String originalText = "This is a text !"; + String formattedArticle = article.format(originalText); + + assertTrue(originalText.toUpperCase().equals(formattedArticle)); + } + + @Test + public void givenAutowiredAnnotation_WhenSetOnConstructor_ThenDependencyValid() { + + ApplicationContext context = new ClassPathXmlApplicationContext("dependencyinjectiontypes-context.xml"); + ArticleWithConstructorInjection article = (ArticleWithConstructorInjection) context.getBean("articleWithConstructorInjectionBean"); + + String originalText = "This is a text !"; + String formattedArticle = article.format(originalText); + + assertTrue(originalText.toUpperCase().equals(formattedArticle)); + } + +}