From 51cc0ad0e8344ac39d6f0731bea3caaf2f9aa0d5 Mon Sep 17 00:00:00 2001 From: medaminefracso Date: Sun, 15 May 2022 12:15:05 +0200 Subject: [PATCH 1/6] added to gitignore new untracked files --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 6143e53..db111de 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,8 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +# other +.idea +target + From 560650df3cea191bb31daa3304b5c779ebc4fdd6 Mon Sep 17 00:00:00 2001 From: medaminefracso Date: Sun, 15 May 2022 12:15:42 +0200 Subject: [PATCH 2/6] added comments/explanations --- ...alLifeWithoutCompletableFutureExample.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/completablefuture/RealLifeWithoutCompletableFutureExample.java b/src/main/java/com/example/completablefuture/RealLifeWithoutCompletableFutureExample.java index 09f11cd..ee5cdf6 100644 --- a/src/main/java/com/example/completablefuture/RealLifeWithoutCompletableFutureExample.java +++ b/src/main/java/com/example/completablefuture/RealLifeWithoutCompletableFutureExample.java @@ -3,31 +3,46 @@ import java.util.ArrayList; import java.util.List; +/** + * In this example, the only thread running is the + * main thread. It sleeps for 2 seconds each time + * the setRating() method is called + */ public class RealLifeWithoutCompletableFutureExample { public static void main(String[] args) { long start = System.currentTimeMillis(); + // creating a list of cars List cars = cars(); + + Long cars_data_processing_start = System.currentTimeMillis(); + // setting the rating of each car cars.forEach(car -> { float rating = rating(car.manufacturerId); car.setRating(rating); }); + Long cars_data_processing_end = System.currentTimeMillis(); + // printing cars cars.forEach(System.out::println); long end = System.currentTimeMillis(); - System.out.println("Took " + (end - start) + " ms."); + System.out.println("The cars data processing to set its ratings took : " + + (cars_data_processing_end - cars_data_processing_start) + " ms."); + System.out.println("The program took " + (end - start) + " ms."); } static float rating(int manufacturer) { try { simulateDelay(); + System.out.println("Thread : " + Thread.currentThread().getName()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } + switch (manufacturer) { case 2: return 4f; @@ -49,7 +64,7 @@ static List cars() { } private static void simulateDelay() throws InterruptedException { - Thread.sleep(5000); + Thread.sleep(2000); } } From 0ca897a453bbf9afc2caef4aba43cd9dbb7378db Mon Sep 17 00:00:00 2001 From: medaminefracso Date: Sun, 15 May 2022 23:02:17 +0200 Subject: [PATCH 3/6] added new Completable Future example The main thread is running too fast so that it doesn't wait for the Completable future thread that is running asynchronously to end --- .../CompletableFutureExamples.java | 269 ------------------ .../CompletableFutureExamples2.java | 34 +++ 2 files changed, 34 insertions(+), 269 deletions(-) delete mode 100644 src/main/java/com/example/completablefuture/CompletableFutureExamples.java create mode 100644 src/main/java/com/example/completablefuture/CompletableFutureExamples2.java diff --git a/src/main/java/com/example/completablefuture/CompletableFutureExamples.java b/src/main/java/com/example/completablefuture/CompletableFutureExamples.java deleted file mode 100644 index c02e22e..0000000 --- a/src/main/java/com/example/completablefuture/CompletableFutureExamples.java +++ /dev/null @@ -1,269 +0,0 @@ -package com.example.completablefuture; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -public class CompletableFutureExamples { - - static ExecutorService executor = Executors.newFixedThreadPool(3, new ThreadFactory() { - int count = 1; - - @Override - public Thread newThread(Runnable runnable) { - return new Thread(runnable, "custom-executor-" + count++); - } - }); - - static Random random = new Random(); - - public static void main(String[] args) { - try { -// allOfAsyncExample(); - } finally { - executor.shutdown(); - } - } - - static void completedFutureExample() { - CompletableFuture cf = CompletableFuture.completedFuture("message"); - assertTrue(cf.isDone()); - assertEquals("message", cf.getNow(null)); - } - - static void completeExceptionallyExample() { - CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase, - CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS)); - CompletableFuture exceptionHandler = cf.handle((s, th) -> { return (th != null) ? "message upon cancel" : ""; }); - cf.completeExceptionally(new RuntimeException("completed exceptionally")); - assertTrue("Was not completed exceptionally", cf.isCompletedExceptionally()); - try { - cf.join(); - fail("Should have thrown an exception"); - } catch (CompletionException ex) { // just for testing - assertEquals("completed exceptionally", ex.getCause().getMessage()); - } - - assertEquals("message upon cancel", exceptionHandler.join()); - } - - static void runAsyncExample() { - CompletableFuture cf = CompletableFuture.runAsync(() -> { - assertTrue(Thread.currentThread().isDaemon()); - randomSleep(); - }); - assertFalse(cf.isDone()); - sleepEnough(); - assertTrue(cf.isDone()); - } - - static void thenApplyExample() { - CompletableFuture cf = CompletableFuture.completedFuture("message").thenApply(s -> { - assertFalse(Thread.currentThread().isDaemon()); - return s.toUpperCase(); - }); - assertEquals("MESSAGE", cf.getNow(null)); - } - - static void thenApplyAsyncExample() { - CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> { - assertTrue(Thread.currentThread().isDaemon()); - randomSleep(); - return s.toUpperCase(); - }); - assertNull(cf.getNow(null)); - assertEquals("MESSAGE", cf.join()); - } - - static void thenApplyAsyncWithExecutorExample() { - CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> { - assertTrue(Thread.currentThread().getName().startsWith("custom-executor-")); - assertFalse(Thread.currentThread().isDaemon()); - randomSleep(); - return s.toUpperCase(); - }, executor); - - assertNull(cf.getNow(null)); - assertEquals("MESSAGE", cf.join()); - } - - static void thenAcceptExample() { - StringBuilder result = new StringBuilder(); - CompletableFuture.completedFuture("thenAccept message") - .thenAccept(s -> result.append(s)); - assertTrue("Result was empty", result.length() > 0); - } - - static void thenAcceptAsyncExample() { - StringBuilder result = new StringBuilder(); - CompletableFuture cf = CompletableFuture.completedFuture("thenAcceptAsync message") - .thenAcceptAsync(s -> result.append(s)); - cf.join(); - assertTrue("Result was empty", result.length() > 0); - } - - static void cancelExample() { - CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase, - CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS)); - CompletableFuture cf2 = cf.exceptionally(throwable -> "canceled message"); - assertTrue("Was not canceled", cf.cancel(true)); - assertTrue("Was not completed exceptionally", cf.isCompletedExceptionally()); - assertEquals("canceled message", cf2.join()); - } - - static void applyToEitherExample() { - String original = "Message"; - CompletableFuture cf1 = CompletableFuture.completedFuture(original) - .thenApplyAsync(s -> delayedUpperCase(s)); - CompletableFuture cf2 = cf1.applyToEither( - CompletableFuture.completedFuture(original).thenApplyAsync(s -> delayedLowerCase(s)), - s -> s + " from applyToEither"); - assertTrue(cf2.join().endsWith(" from applyToEither")); - } - - static void acceptEitherExample() { - String original = "Message"; - StringBuilder result = new StringBuilder(); - CompletableFuture cf = CompletableFuture.completedFuture(original) - .thenApplyAsync(s -> delayedUpperCase(s)) - .acceptEither(CompletableFuture.completedFuture(original).thenApplyAsync(s -> delayedLowerCase(s)), - s -> result.append(s).append("acceptEither")); - cf.join(); - assertTrue("Result was empty", result.toString().endsWith("acceptEither")); - } - - static void runAfterBothExample() { - String original = "Message"; - StringBuilder result = new StringBuilder(); - CompletableFuture.completedFuture(original).thenApply(String::toUpperCase).runAfterBoth( - CompletableFuture.completedFuture(original).thenApply(String::toLowerCase), - () -> result.append("done")); - assertTrue("Result was empty", result.length() > 0); - } - - static void thenAcceptBothExample() { - String original = "Message"; - StringBuilder result = new StringBuilder(); - CompletableFuture.completedFuture(original).thenApply(String::toUpperCase).thenAcceptBoth( - CompletableFuture.completedFuture(original).thenApply(String::toLowerCase), - (s1, s2) -> result.append(s1 + s2)); - assertEquals("MESSAGEmessage", result.toString()); - } - - static void thenCombineExample() { - String original = "Message"; - CompletableFuture cf = CompletableFuture.completedFuture(original).thenApply(s -> delayedUpperCase(s)) - .thenCombine(CompletableFuture.completedFuture(original).thenApply(s -> delayedLowerCase(s)), - (s1, s2) -> s1 + s2); - assertEquals("MESSAGEmessage", cf.getNow(null)); - } - - static void thenCombineAsyncExample() { - String original = "Message"; - CompletableFuture cf = CompletableFuture.completedFuture(original) - .thenApplyAsync(s -> delayedUpperCase(s)) - .thenCombine(CompletableFuture.completedFuture(original).thenApplyAsync(s -> delayedLowerCase(s)), - (s1, s2) -> s1 + s2); - assertEquals("MESSAGEmessage", cf.join()); - } - - static void thenComposeExample() { - String original = "Message"; - CompletableFuture cf = CompletableFuture.completedFuture(original).thenApply(s -> delayedUpperCase(s)) - .thenCompose(upper -> CompletableFuture.completedFuture(original).thenApply(s -> delayedLowerCase(s)) - .thenApply(s -> upper + s)); - assertEquals("MESSAGEmessage", cf.join()); - } - - static void anyOfExample() { - StringBuilder result = new StringBuilder(); - List messages = Arrays.asList("a", "b", "c"); - List> futures = messages.stream() - .map(msg -> CompletableFuture.completedFuture(msg).thenApply(s -> delayedUpperCase(s))) - .collect(Collectors.toList()); - CompletableFuture.anyOf(futures.toArray(new CompletableFuture[futures.size()])).whenComplete((res, th) -> { - if(th == null) { - assertTrue(isUpperCase((String) res)); - result.append(res); - } - }); - assertTrue("Result was empty", result.length() > 0); - } - - static void allOfExample() { - StringBuilder result = new StringBuilder(); - List messages = Arrays.asList("a", "b", "c"); - List> futures = messages.stream() - .map(msg -> CompletableFuture.completedFuture(msg).thenApply(s -> delayedUpperCase(s))) - .collect(Collectors.toList()); - CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).whenComplete((v, th) -> { - futures.forEach(cf -> assertTrue(isUpperCase(cf.getNow(null)))); - result.append("done"); - }); - assertTrue("Result was empty", result.length() > 0); - } - - static void allOfAsyncExample() { - StringBuilder result = new StringBuilder(); - List messages = Arrays.asList("a", "b", "c"); - List> futures = messages.stream() - .map(msg -> CompletableFuture.completedFuture(msg).thenApplyAsync(s -> delayedUpperCase(s))) - .collect(Collectors.toList()); - CompletableFuture allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])) - .whenComplete((v, th) -> { - futures.forEach(cf -> assertTrue(isUpperCase(cf.getNow(null)))); - result.append("done"); - }); - allOf.join(); - assertTrue("Result was empty", result.length() > 0); - } - - private static boolean isUpperCase(String s) { - for (int i = 0; i < s.length(); i++) { - if (Character.isLowerCase(s.charAt(i))) { - return false; - } - } - return true; - } - - private static String delayedUpperCase(String s) { - randomSleep(); - return s.toUpperCase(); - } - - private static String delayedLowerCase(String s) { - randomSleep(); - return s.toLowerCase(); - } - - private static void randomSleep() { - try { - Thread.sleep(random.nextInt(1000)); - } catch (InterruptedException e) { - // ... - } - } - - private static void sleepEnough() { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - // ... - } - } - -} diff --git a/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java b/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java new file mode 100644 index 0000000..20ff6cb --- /dev/null +++ b/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java @@ -0,0 +1,34 @@ +package com.example.completablefuture; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +public class CompletableFutureExamples2 { + public static void main(String[] args) { + + System.out.println("Beginning of the program"); + + CompletableFuture.supplyAsync(new Supplier() { + + @Override + public Integer get() { + return longNetworkProcess(5); + } + }).thenAccept(value -> System.out.println(value)); + + System.out.println("End of the program"); + + //System.out.println("The solution is " + solution); + } + + public static int longNetworkProcess(int value) { + try { + Thread.sleep(10000); + } + catch(InterruptedException e) { + e.printStackTrace(); + } + + return value * 10; + } +} From b6ab2ac7e76f11449712e8ccb20390120d624e20 Mon Sep 17 00:00:00 2001 From: medaminefracso Date: Sun, 15 May 2022 23:04:46 +0200 Subject: [PATCH 4/6] added a comment --- .../completablefuture/RealLifeCompletableFutureExample.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/example/completablefuture/RealLifeCompletableFutureExample.java b/src/main/java/com/example/completablefuture/RealLifeCompletableFutureExample.java index e27a531..a6357a3 100644 --- a/src/main/java/com/example/completablefuture/RealLifeCompletableFutureExample.java +++ b/src/main/java/com/example/completablefuture/RealLifeCompletableFutureExample.java @@ -12,6 +12,8 @@ public static void main(String[] args) { long start = System.currentTimeMillis(); cars().thenCompose(cars -> { + + // set the rating of each car List> updatedCars = cars.stream() .map(car -> rating(car.manufacturerId).thenApply(r -> { car.setRating(r); @@ -20,8 +22,10 @@ public static void main(String[] args) { CompletableFuture done = CompletableFuture .allOf(updatedCars.toArray(new CompletableFuture[updatedCars.size()])); + return done.thenApply(v -> updatedCars.stream().map(CompletionStage::toCompletableFuture) .map(CompletableFuture::join).collect(Collectors.toList())); + }).whenComplete((cars, th) -> { if (th == null) { cars.forEach(System.out::println); @@ -43,6 +47,7 @@ static CompletionStage rating(int manufacturer) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } + switch (manufacturer) { case 2: return 4f; @@ -61,6 +66,7 @@ static CompletionStage> cars() { carList.add(new Car(1, 3, "Fiesta", 2017)); carList.add(new Car(2, 7, "Camry", 2014)); carList.add(new Car(3, 2, "M2", 2008)); + return CompletableFuture.supplyAsync(() -> carList); } From 3058ed331f3715b4132de49d1e57d106d0937735 Mon Sep 17 00:00:00 2001 From: medaminefracso Date: Sun, 15 May 2022 23:52:59 +0200 Subject: [PATCH 5/6] Example of main thread and a concurrent thread The main thread sleeps a bit to wait for the other thread to complete. The main thread output shows up before the completableFuture result --- .../CompletableFutureExamples2.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java b/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java index 20ff6cb..bbc8f11 100644 --- a/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java +++ b/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java @@ -16,19 +16,22 @@ public Integer get() { } }).thenAccept(value -> System.out.println(value)); + sleep(3); System.out.println("End of the program"); - - //System.out.println("The solution is " + solution); } public static int longNetworkProcess(int value) { + sleep(3); + + return value * 10; + } + + public static void sleep(int seconds) { try { - Thread.sleep(10000); + Thread.sleep(seconds * 1000); } catch(InterruptedException e) { e.printStackTrace(); } - - return value * 10; } } From 5c668add8bb923cd2638e8c689e0d0b94fa4ccb7 Mon Sep 17 00:00:00 2001 From: medaminefracso Date: Sun, 15 May 2022 23:55:41 +0200 Subject: [PATCH 6/6] Example2 : main thread and a concurrent thread In this case, the main thread waits for a longer time and it shows up after the completableFuture output/result --- .../example/completablefuture/CompletableFutureExamples2.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java b/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java index bbc8f11..89dc3ee 100644 --- a/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java +++ b/src/main/java/com/example/completablefuture/CompletableFutureExamples2.java @@ -16,7 +16,7 @@ public Integer get() { } }).thenAccept(value -> System.out.println(value)); - sleep(3); + sleep(5); System.out.println("End of the program"); }