diff --git a/concurrent/Baked.java b/concurrent/Baked.java new file mode 100644 index 00000000..ab336605 --- /dev/null +++ b/concurrent/Baked.java @@ -0,0 +1,31 @@ +// concurrent/Baked.java +// (c)2016 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +import java.util.concurrent.*; +import java.util.stream.*; +import onjava.Nap; + +public class Baked { + static class Pan {} + static Pan pan(Batter b) { + new Nap(100); + return new Pan(); + } + static Baked heat(Pan p) { + new Nap(100); + return new Baked(); + } + static CompletableFuture + bake(CompletableFuture cfb) { + return cfb + .thenApplyAsync(Baked::pan) + .thenApplyAsync(Baked::heat); + } + public static + Stream> batch() { + CompletableFuture batter = Batter.mix(); + return Stream.of(bake(batter), bake(batter), + bake(batter), bake(batter)); + } +} diff --git a/concurrent/Batter.java b/concurrent/Batter.java new file mode 100644 index 00000000..d05ece3e --- /dev/null +++ b/concurrent/Batter.java @@ -0,0 +1,34 @@ +// concurrent/Batter.java +// (c)2016 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +import java.util.concurrent.*; +import onjava.Nap; + +public class Batter { + static class Eggs {} + static class Milk {} + static class Sugar {} + static class Flour {} + static T prepare(T ingredient) { + new Nap(100); + return ingredient; + } + static CompletableFuture cf(T ingredient) { + return CompletableFuture + .completedFuture(ingredient) + .thenApply(Batter::prepare); + } + public static CompletableFuture mix() { + CompletableFuture eggs = cf(new Eggs()); + CompletableFuture milk = cf(new Milk()); + CompletableFuture sugar = cf(new Sugar()); + CompletableFuture flour = cf(new Flour()); + CompletableFuture + .allOf(eggs, milk, sugar, flour) + .join(); + new Nap(100); // Mixing time + return + CompletableFuture.completedFuture(new Batter()); + } +} diff --git a/concurrent/Breakable.java b/concurrent/Breakable.java new file mode 100644 index 00000000..91888333 --- /dev/null +++ b/concurrent/Breakable.java @@ -0,0 +1,26 @@ +// concurrent/Breakable.java +// (c)2016 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +import java.util.concurrent.*; + +public class Breakable { + String id; + private int failcount; + public Breakable(String id, int failcount) { + this.id = id; + this.failcount = failcount; + } + @Override + public String toString() { + return "Breakable_" + id + + " [" + failcount + "]"; + } + public static Breakable work(Breakable b) { + if(--b.failcount == 0) + throw new RuntimeException( + "Breakable_" + b.id + " failed"); + System.out.println(b); + return b; + } +} diff --git a/concurrent/CatchCompletableExceptions.java b/concurrent/CatchCompletableExceptions.java new file mode 100644 index 00000000..30f05cfa --- /dev/null +++ b/concurrent/CatchCompletableExceptions.java @@ -0,0 +1,79 @@ +// concurrent/CatchCompletableExceptions.java +// (c)2016 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +import java.util.concurrent.*; +import onjava.Nap; + +public class CatchCompletableExceptions { + static void handleException(int failcount) { + // Call Function only if there's an exception, + // Must produce same type as came in: + CompletableExceptions + .test("exceptionally", failcount) + .exceptionally((ex) -> { // Function + if(ex == null) + System.out.println("I don't get it yet"); + return new Breakable(ex.getMessage(), 0); + }) + .thenAccept(str -> + System.out.println("result: " + str)); + + // Create a new result (recover): + CompletableExceptions + .test("handle", failcount) + .handle((result, fail) -> { // BiFunction + if(fail != null) + return "Failure recovery object"; + else + return result + " is good"; + }) + .thenAccept(str -> + System.out.println("result: " + str)); + + // Do something but pass the same result through: + CompletableExceptions + .test("whenComplete", failcount) + .whenComplete((result, fail) -> { // BiConsumer + if(fail != null) + System.out.println("It failed"); + else + System.out.println(result + " OK"); + }) + .thenAccept(r -> + System.out.println("result: " + r)); + } + public static void main(String[] args) { + System.out.println("**** Failure Mode ****"); + handleException(2); + System.out.println("**** Success Mode ****"); + handleException(0); + } +} +/* Output: +**** Failure Mode **** +Breakable_exceptionally [1] +result: Breakable_java.lang.RuntimeException: +Breakable_exceptionally failed [0] +Breakable_handle [1] +result: Failure recovery object +Breakable_whenComplete [1] +It failed +**** Success Mode **** +Breakable_exceptionally [-1] +Breakable_exceptionally [-2] +Breakable_exceptionally [-3] +Breakable_exceptionally [-4] +result: Breakable_exceptionally [-4] +Breakable_handle [-1] +Breakable_handle [-2] +Breakable_handle [-3] +Breakable_handle [-4] +result: Breakable_handle [-4] is good +Breakable_whenComplete [-1] +Breakable_whenComplete [-2] +Breakable_whenComplete [-3] +Breakable_whenComplete [-4] +Breakable_whenComplete [-4] OK +result: Breakable_whenComplete [-4] +*/ diff --git a/concurrent/Chopstick.java b/concurrent/Chopstick.java deleted file mode 100644 index 2c853a97..00000000 --- a/concurrent/Chopstick.java +++ /dev/null @@ -1,19 +0,0 @@ -// concurrent/Chopstick.java -// (c)2016 MindView LLC: see Copyright.txt -// We make no guarantees that this code is fit for any purpose. -// Visit http://OnJava8.com for more book information. -// Chopsticks for dining philosophers - -public class Chopstick { - private boolean taken = false; - public synchronized - void take() throws InterruptedException { - while(taken) - wait(); - taken = true; - } - public synchronized void drop() { - taken = false; - notifyAll(); - } -} diff --git a/concurrent/CompletableApply.java b/concurrent/CompletableApply.java index 504d4e2c..4e98eb06 100644 --- a/concurrent/CompletableApply.java +++ b/concurrent/CompletableApply.java @@ -19,3 +19,9 @@ public class CompletableApply { cf4.thenApply(Machina::work); } } +/* Output: +Machina0: ONE +Machina0: TWO +Machina0: THREE +Machina0: complete +*/ diff --git a/concurrent/CompletableExceptions.java b/concurrent/CompletableExceptions.java new file mode 100644 index 00000000..a1497fc2 --- /dev/null +++ b/concurrent/CompletableExceptions.java @@ -0,0 +1,69 @@ +// concurrent/CompletableExceptions.java +// (c)2016 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +import java.util.concurrent.*; +import onjava.Nap; + +public class CompletableExceptions { + static CompletableFuture + test(String id, int failcount) { + return + CompletableFuture.completedFuture( + new Breakable(id, failcount)) + .thenApply(Breakable::work) + .thenApply(Breakable::work) + .thenApply(Breakable::work) + .thenApply(Breakable::work); + } + public static void main(String[] args) { + // Exceptions don't appear ... + test("A", 1); + test("B", 2); + test("C", 3); + test("D", 4); + test("E", 5); + // ... until you try to fetch the value: + try { + test("F", 2).get(); // or join() + } catch(Exception e) { + System.out.println(e.getMessage()); + } + // Test for exceptions: + System.out.println( + test("G", 2).isCompletedExceptionally()); + // Counts as "done": + System.out.println(test("H", 2).isDone()); + // Force an exception: + CompletableFuture cfi = + new CompletableFuture<>(); + System.out.println("done? " + cfi.isDone()); + cfi.completeExceptionally( + new RuntimeException("forced")); + try { + cfi.get(); + } catch(Exception e) { + System.out.println(e.getMessage()); + } + } +} +/* Output: +Breakable_B [1] +Breakable_C [2] +Breakable_C [1] +Breakable_D [3] +Breakable_D [2] +Breakable_D [1] +Breakable_E [4] +Breakable_E [3] +Breakable_E [2] +Breakable_E [1] +Breakable_F [1] +java.lang.RuntimeException: Breakable_F failed +Breakable_G [1] +true +Breakable_H [1] +true +done? false +java.lang.RuntimeException: forced +*/ diff --git a/concurrent/CompletableOperations.java b/concurrent/CompletableOperations.java index ada4a2f1..27f0a96d 100644 --- a/concurrent/CompletableOperations.java +++ b/concurrent/CompletableOperations.java @@ -5,10 +5,10 @@ import java.util.concurrent.*; public class CompletableOperations { - static CompletableFuture cfi() { + static CompletableFuture cfi(int i) { return CompletableFuture.completedFuture( - new Integer(1)); + new Integer(i)); } // Get and show value stored in a CF: static void showr(CompletableFuture c) { @@ -29,11 +29,60 @@ public class CompletableOperations { } } public static void main(String[] args) { - showr(cfi()); // Basic test - showr(cfi().thenApplyAsync(i -> i + 42)); - voidr(cfi().runAsync(() -> System.out.println("run"))); - CompletableFuture c = cfi(); + showr(cfi(1)); // Basic test + voidr(cfi(2).runAsync(() -> + System.out.println("runAsync"))); + voidr(cfi(3).thenRunAsync(() -> + System.out.println("thenRunAsync"))); + showr(CompletableFuture.supplyAsync(() -> 99)); + voidr(cfi(4).thenAcceptAsync(i -> + System.out.println("thenAcceptAsync: " + i))); + showr(cfi(5).thenApplyAsync(i -> i + 42)); + showr(cfi(6).thenComposeAsync(i -> cfi(i + 99))); + CompletableFuture c = cfi(7); c.obtrudeValue(111); showr(c); + showr(cfi(8).toCompletableFuture()); + c = new CompletableFuture<>(); + c.complete(9); + showr(c); + c = new CompletableFuture<>(); + c.cancel(true); + System.out.println("cancelled: " + + c.isCancelled()); + System.out.println("completed exceptionally: " + + c.isCompletedExceptionally()); + System.out.println("done: " + c.isDone()); + System.out.println(c); + c = new CompletableFuture<>(); + System.out.println(c.getNow(777)); + c = new CompletableFuture<>(); + c.thenApplyAsync(i -> i + 42) + .thenApplyAsync(i -> i * 12); + System.out.println("dependents: " + + c.getNumberOfDependents()); + c.thenApplyAsync(i -> i / 2); + System.out.println("dependents: " + + c.getNumberOfDependents()); } } +/* Output: +1 +runAsync +thenRunAsync +99 +thenAcceptAsync: 4 +47 +105 +111 +8 +9 +cancelled: true +completed exceptionally: true +done: true +java.util.concurrent.CompletableFuture@404b9385[Completed +exceptionally] +777 +dependents: 1 +dependents: 2 +*/ diff --git a/concurrent/CompletablePizza.java b/concurrent/CompletablePizza.java index 48b678fa..fcac4414 100644 --- a/concurrent/CompletablePizza.java +++ b/concurrent/CompletablePizza.java @@ -42,4 +42,47 @@ public class CompletablePizza { } } /* Output: +/* Output: +56 +Pizza 0: ROLLED +Pizza 1: ROLLED +Pizza 4: ROLLED +Pizza 2: ROLLED +Pizza 3: ROLLED +Pizza 0: SAUCED +Pizza 3: SAUCED +Pizza 2: SAUCED +Pizza 4: SAUCED +Pizza 1: SAUCED +Pizza 0: CHEESED +Pizza 4: CHEESED +Pizza 2: CHEESED +Pizza 3: CHEESED +Pizza 1: CHEESED +Pizza 0: TOPPED +Pizza 4: TOPPED +Pizza 1: TOPPED +Pizza 3: TOPPED +Pizza 2: TOPPED +Pizza 0: BAKED +Pizza 4: BAKED +Pizza 3: BAKED +Pizza 1: BAKED +Pizza 2: BAKED +Pizza 0: SLICED +Pizza 2: SLICED +Pizza 4: SLICED +Pizza 1: SLICED +Pizza 3: SLICED +Pizza 0: BOXED +Pizza0: complete +Pizza 4: BOXED +Pizza 3: BOXED +Pizza 2: BOXED +Pizza 1: BOXED +Pizza1: complete +Pizza2: complete +Pizza3: complete +Pizza4: complete +1659 */ diff --git a/concurrent/DeadlockingDiningPhilosophers.java b/concurrent/DeadlockingDiningPhilosophers.java deleted file mode 100644 index 1870a745..00000000 --- a/concurrent/DeadlockingDiningPhilosophers.java +++ /dev/null @@ -1,60 +0,0 @@ -// concurrent/DeadlockingDiningPhilosophers.java -// (c)2016 MindView LLC: see Copyright.txt -// We make no guarantees that this code is fit for any purpose. -// Visit http://OnJava8.com for more book information. -// Demonstrates how deadlock can be hidden in a program -// {java DeadlockingDiningPhilosophers 0 5 timeout} -import java.util.concurrent.*; -import onjava.Nap; - -public class DeadlockingDiningPhilosophers { - public static void main(String[] args) { - int ponder = 5; - if(args.length > 0) - ponder = Integer.parseInt(args[0]); - int size = 5; - if(args.length > 1) - size = Integer.parseInt(args[1]); - ExecutorService es = Executors.newCachedThreadPool(); - Chopstick[] sticks = new Chopstick[size]; - for(int i = 0; i < size; i++) - sticks[i] = new Chopstick(); - for(int i = 0; i < size; i++) - es.execute(new Philosopher( - sticks[i], sticks[(i+1) % size], i, ponder)); - if(args.length == 3 && args[2].equals("timeout")) - new Nap(5000); - else { - System.out.println("Press 'Enter' to quit"); - try { - System.in.read(); - } catch(Exception e) { - throw new RuntimeException(e); - } - } - es.shutdownNow(); - } -} -/* Output: (First and Last 10 Lines) -Philosopher 0 thinking -Philosopher 4 thinking -Philosopher 1 thinking -Philosopher 3 thinking -Philosopher 2 thinking -Philosopher 3 grabbing right -Philosopher 1 grabbing right -Philosopher 4 grabbing right -Philosopher 0 grabbing right -Philosopher 4 grabbing left -...________...________...________...________... -Philosopher 3 grabbing left -Philosopher 1 grabbing left -Philosopher 4 grabbing left -Philosopher 2 grabbing left -Philosopher 0 grabbing left -Philosopher 1 exiting via interrupt -Philosopher 4 exiting via interrupt -Philosopher 3 exiting via interrupt -Philosopher 2 exiting via interrupt -Philosopher 0 exiting via interrupt -*/ diff --git a/concurrent/DiningPhilosophers.java b/concurrent/DiningPhilosophers.java new file mode 100644 index 00000000..49e0b96d --- /dev/null +++ b/concurrent/DiningPhilosophers.java @@ -0,0 +1,64 @@ +// concurrent/DiningPhilosophers.java +// (c)2016 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// Deadlock can be hidden in a program +import java.util.stream.*; +import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.*; + +public class DiningPhilosophers { + static void stopAfter(int secs) { + ScheduledExecutorService sched = + Executors.newScheduledThreadPool(1); + sched.schedule( () -> { + System.out.println("Timeout"); + Philosopher.running.set(false); + sched.shutdownNow(); + System.exit(0); + }, secs, SECONDS); + } + public static void main(String[] args) + throws Exception { + stopAfter(3); + try { + IntStream.range(0, Philosopher.QUANTITY) + .mapToObj(Philosopher::new) + .map(CompletableFuture::runAsync) + .collect(Collectors.toList()) + .forEach(CompletableFuture::join); + } catch(CompletionException ex) { + Philosopher.running.set(false); + System.out.println("Broken out of deadlock"); + System.out.println("..."); + } + Philosopher.trace.stream() + .skip(Philosopher.trace.size() - 20) + .forEach(System.out::println); + } +} +/* Output: +Broken out of deadlock +... +P2 grabbing right +P1 grabbing left +P3 eating +P3 thinking +P3 grabbing right +P4 eating +P2 grabbing left +P4 thinking +P0 eating +P4 grabbing right +P3 grabbing left +P0 thinking +P0 grabbing right +P4 grabbing left +P0 grabbing left +P1 eating +P2 eating +P3 eating +P0 eating +P4 eating +Timeout +*/ diff --git a/concurrent/DualCompletableOperations.java b/concurrent/DualCompletableOperations.java index 4fdefedd..aff6348d 100644 --- a/concurrent/DualCompletableOperations.java +++ b/concurrent/DualCompletableOperations.java @@ -5,42 +5,108 @@ import java.util.concurrent.*; public class DualCompletableOperations { - static - CompletableFuture makeCF(int id) { - return - CompletableFuture.completedFuture( - new RandomWork(id)) - .thenApplyAsync(RandomWork::work); - } - static CompletableFuture cfA, cfB; - static int count = 0; + static CompletableFuture cfA, cfB; static void init() { - cfA = makeCF(count++); - cfB = makeCF(count++); + cfA = Workable.make("A", 150); + cfB = Workable.make("B", 100); // Always wins } static void join() { cfA.join(); cfB.join(); + System.out.println("*****************"); } public static void main(String[] args) { - init(); - cfA.runAfterBothAsync(cfB, () -> - System.out.println("Completed Both")); - join(); - init(); cfA.runAfterEitherAsync(cfB, () -> - System.out.println("Completed Either")); + System.out.println("runAfterEither")); join(); init(); - cfA.applyToEitherAsync(cfB, rw -> { - System.out.println("applyToEither: " + rw); - return rw; + cfA.runAfterBothAsync(cfB, () -> + System.out.println("runAfterBoth")); + join(); + + init(); + cfA.applyToEitherAsync(cfB, w -> { + System.out.println("applyToEither: " + w); + return w; }); join(); + init(); + cfA.acceptEitherAsync(cfB, w -> { + System.out.println("acceptEither: " + w); + }); + join(); + + init(); + cfA.thenAcceptBothAsync(cfB, (w1, w2) -> { + System.out.println("thenAcceptBoth: " + + w1 + ", " + w2); + }); + join(); + + init(); + cfA.thenCombineAsync(cfB, (w1, w2) -> { + System.out.println("thenCombine: " + + w1 + ", " + w2); + return w1; + }); + join(); + + init(); + CompletableFuture + cfC = Workable.make("C", 75), + cfD = Workable.make("D", 99); + CompletableFuture.anyOf(cfA, cfB, cfC, cfD) + .thenRunAsync(() -> + System.out.println("anyOf")); + join(); + + init(); + cfC = Workable.make("C", 75); + cfD = Workable.make("D", 99); + CompletableFuture.allOf(cfA, cfB, cfC, cfD) + .thenRunAsync(() -> + System.out.println("allOf")); + join(); } } /* Output: +Workable[BW] +runAfterEither +Workable[AW] +***************** +Workable[BW] +Workable[AW] +***************** +runAfterBoth +Workable[BW] +applyToEither: Workable[BW] +Workable[AW] +***************** +Workable[BW] +acceptEither: Workable[BW] +Workable[AW] +***************** +Workable[BW] +Workable[AW] +***************** +thenAcceptBoth: Workable[AW], Workable[BW] +Workable[BW] +Workable[AW] +***************** +thenCombine: Workable[AW], Workable[BW] +Workable[CW] +anyOf +Workable[DW] +Workable[BW] +Workable[AW] +***************** +Workable[CW] +Workable[DW] +Workable[BW] +Workable[AW] +***************** +allOf */ diff --git a/concurrent/FixedDiningPhilosophers.java b/concurrent/FixedDiningPhilosophers.java deleted file mode 100644 index 7d2cb899..00000000 --- a/concurrent/FixedDiningPhilosophers.java +++ /dev/null @@ -1,65 +0,0 @@ -// concurrent/FixedDiningPhilosophers.java -// (c)2016 MindView LLC: see Copyright.txt -// We make no guarantees that this code is fit for any purpose. -// Visit http://OnJava8.com for more book information. -// Dining philosophers without deadlock -// {java FixedDiningPhilosophers 5 5 timeout} -import java.util.concurrent.*; -import onjava.Nap; - -public class FixedDiningPhilosophers { - public static void - main(String[] args) { - int ponder = 5; - if(args.length > 0) - ponder = Integer.parseInt(args[0]); - int size = 5; - if(args.length > 1) - size = Integer.parseInt(args[1]); - ExecutorService es = Executors.newCachedThreadPool(); - Chopstick[] sticks = new Chopstick[size]; - for(int i = 0; i < size; i++) - sticks[i] = new Chopstick(); - for(int i = 0; i < size; i++) - if(i < (size-1)) - es.execute(new Philosopher( - sticks[i], sticks[i+1], i, ponder)); - else - es.execute(new Philosopher( - sticks[0], sticks[i], i, ponder)); - if(args.length == 3 && args[2].equals("timeout")) - new Nap(5000); - else { - System.out.println("Press 'Enter' to quit"); - try { - System.in.read(); - } catch(Exception e) { - throw new RuntimeException(e); - } - } - es.shutdownNow(); - } -} -/* Output: (First and Last 10 Lines) -Philosopher 1 thinking -Philosopher 4 thinking -Philosopher 2 thinking -Philosopher 0 thinking -Philosopher 3 thinking -Philosopher 1 grabbing right -Philosopher 2 grabbing right -Philosopher 4 grabbing right -Philosopher 4 grabbing left -Philosopher 4 eating -...________...________...________...________... -Philosopher 1 thinking -Philosopher 0 grabbing left -Philosopher 0 eating -Philosopher 2 eating -Philosopher 1 grabbing right -Philosopher 3 exiting via interrupt -Philosopher 1 exiting via interrupt -Philosopher 2 exiting via interrupt -Philosopher 0 exiting via interrupt -Philosopher 4 exiting via interrupt -*/ diff --git a/concurrent/FrostedCake.java b/concurrent/FrostedCake.java new file mode 100644 index 00000000..f4926324 --- /dev/null +++ b/concurrent/FrostedCake.java @@ -0,0 +1,31 @@ +// concurrent/FrostedCake.java +// (c)2016 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +import java.util.concurrent.*; +import java.util.function.*; +import java.util.stream.*; +import onjava.Nap; + +class Frosting { + private Frosting() {} + static CompletableFuture make() { + new Nap(100); + return CompletableFuture + .completedFuture(new Frosting()); + } +} + +public class FrostedCake { + public FrostedCake(Baked baked, Frosting frosting) { + new Nap(100); + } + public static void main(String[] args) { + Baked.batch().forEach(baked -> baked + .thenCombineAsync(Frosting.make(), + (cake, frosting) -> + new FrostedCake(cake, frosting)) + .thenAcceptAsync(System.out::println).join()); + // Need to rewrite... + } +} diff --git a/concurrent/ParallelPrime.java b/concurrent/ParallelPrime.java index 597f645e..3c16a8eb 100644 --- a/concurrent/ParallelPrime.java +++ b/concurrent/ParallelPrime.java @@ -31,3 +31,7 @@ public class ParallelPrime { StandardOpenOption.CREATE); } } +/* Output: +/* Output: +616 +*/ diff --git a/concurrent/ParallelStreamPuzzle.java b/concurrent/ParallelStreamPuzzle.java index d9052087..f7902731 100644 --- a/concurrent/ParallelStreamPuzzle.java +++ b/concurrent/ParallelStreamPuzzle.java @@ -23,3 +23,6 @@ public class ParallelStreamPuzzle { System.out.println(x); } } +/* Output: +[2, 8, 21, 24, 27, 30, 33, 37, 40, 43] +*/ diff --git a/concurrent/Philosopher.java b/concurrent/Philosopher.java index 4b00bb59..a7c570ac 100644 --- a/concurrent/Philosopher.java +++ b/concurrent/Philosopher.java @@ -2,48 +2,58 @@ // (c)2016 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. -// A dining philosopher import java.util.*; -import onjava.Nap; +import java.util.stream.*; +import java.util.concurrent.*; +import static java.util.concurrent.TimeUnit.*; +import java.util.concurrent.atomic.*; -public class Philosopher implements Runnable { - private Chopstick left; - private Chopstick right; - private final int id; - private final int ponderFactor; - private SplittableRandom rand = new SplittableRandom(47); - private void pause() { - if(ponderFactor == 0) return; - new Nap(rand.nextInt(ponderFactor * 250)); - } - public Philosopher(Chopstick left, Chopstick right, - int ident, int ponder) { - this.left = left; - this.right = right; - id = ident; - ponderFactor = ponder; +class Philosopher implements Runnable { + static class Chopstick {} + public static final int QUANTITY = 5; + static Queue trace = + new ConcurrentLinkedQueue<>(); + static AtomicBoolean running = + new AtomicBoolean(true); + public static + List> chopsticks = + IntStream.range(0, Philosopher.QUANTITY) + .mapToObj(i -> { + BlockingQueue bd = + new ArrayBlockingQueue<>(1); + bd.add(new Chopstick()); + return bd; + }) + .collect(Collectors.toList()); + private final int seatNumber; + private final int left, right; + public Philosopher(int seatNumber) { + this.seatNumber = left = seatNumber; + right = (seatNumber + 1) % QUANTITY; } @Override public void run() { try { - while(!Thread.interrupted()) { - System.out.println(this + " " + "thinking"); - pause(); + while(running.get()) { + trace.add(this + " thinking"); // Philosopher becomes hungry - System.out.println(this + " " + "grabbing right"); - right.take(); - System.out.println(this + " " + "grabbing left"); - left.take(); - System.out.println(this + " " + "eating"); - pause(); - right.drop(); - left.drop(); + trace.add(this + " grabbing right"); + Chopstick rightStick = + chopsticks.get(right).poll(2, SECONDS); + trace.add(this + " grabbing left"); + Chopstick leftStick = + chopsticks.get(left).poll(2, SECONDS); + trace.add(this + " eating"); + // Finished, return chopsticks to table: + chopsticks.get(right).put(rightStick); + chopsticks.get(left).put(leftStick); } } catch(InterruptedException e) { - System.out.println( - this + " " + "exiting via interrupt"); + trace.add("exiting via interrupt"); } } @Override - public String toString() { return "Philosopher " + id; } + public String toString() { + return "P" + seatNumber; + } } diff --git a/concurrent/QuittingTasks.java b/concurrent/QuittingTasks.java index 1f74c93d..92e8f331 100644 --- a/concurrent/QuittingTasks.java +++ b/concurrent/QuittingTasks.java @@ -22,3 +22,14 @@ public class QuittingTasks { es.shutdown(); } } +/* Output: +125 148 115 127 120 118 106 140 77 119 97 80 143 17 92 147 +89 123 16 12 138 25 13 101 135 96 76 73 130 133 37 132 134 +149 137 122 29 49 60 40 142 131 53 1 98 145 126 65 5 64 82 +79 68 86 141 61 128 22 7 26 19 139 114 146 14 15 43 34 10 +75 87 90 31 47 38 62 18 63 41 42 144 66 23 6 4 91 70 83 102 +103 54 69 74 56 71 94 88 78 81 57 52 93 45 48 44 32 28 36 +33 104 105 112 109 100 117 24 108 21 116 20 9 85 8 84 72 +107 113 121 124 136 129 99 95 55 3 27 2 59 67 50 58 51 39 +30 35 46 110 111 11 +*/ diff --git a/concurrent/RandomWork.java b/concurrent/RandomWork.java deleted file mode 100644 index f09922cc..00000000 --- a/concurrent/RandomWork.java +++ /dev/null @@ -1,22 +0,0 @@ -// concurrent/RandomWork.java -// (c)2016 MindView LLC: see Copyright.txt -// We make no guarantees that this code is fit for any purpose. -// Visit http://OnJava8.com for more book information. -import java.util.*; -import onjava.Nap; - -public class RandomWork { - private static SplittableRandom rand = - new SplittableRandom(47); - private final int id; - public RandomWork(int id) { this.id = id; } - public static RandomWork work(RandomWork r) { - new Nap(rand.nextInt(250)); - System.out.println(r); - return r; - } - @Override - public String toString() { - return "RandomWork " + id; - } -} diff --git a/concurrent/Summing2.java b/concurrent/Summing2.java index eb214572..a7da46e3 100644 --- a/concurrent/Summing2.java +++ b/concurrent/Summing2.java @@ -36,8 +36,8 @@ public class Summing2 { } /* Output: 200000010000000 -Array Stream Sum: 112ms -Parallel: 28ms -Basic Sum: 33ms -parallelPrefix: 60ms +Array Stream Sum: 22ms +Parallel: 21ms +Basic Sum: 16ms +parallelPrefix: 116ms */ diff --git a/concurrent/Workable.java b/concurrent/Workable.java new file mode 100644 index 00000000..87d7abdf --- /dev/null +++ b/concurrent/Workable.java @@ -0,0 +1,32 @@ +// concurrent/Workable.java +// (c)2016 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +import java.util.concurrent.*; +import onjava.Nap; + +public class Workable { + String id; + final int duration; + public Workable(String id, int duration) { + this.id = id; + this.duration = duration; + } + @Override + public String toString() { + return "Workable[" + id + "]"; + } + public static Workable work(Workable tt) { + new Nap(tt.duration); // Milliseconds + tt.id = tt.id + "W"; + System.out.println(tt); + return tt; + } + public static CompletableFuture + make(String id, int duration) { + return + CompletableFuture.completedFuture( + new Workable(id, duration)) + .thenApplyAsync(Workable::work); + } +} diff --git a/gradle/subprojects.gradle b/gradle/subprojects.gradle index 8972377b..5a77a037 100644 --- a/gradle/subprojects.gradle +++ b/gradle/subprojects.gradle @@ -14,7 +14,7 @@ project(':understandingcollections') { } } -project(':concurrent') { +project(':lowlevel') { dependencies { compile project(':enums') } diff --git a/concurrent/BankTellerSimulation.java b/lowlevel/BankTellerSimulation.java similarity index 99% rename from concurrent/BankTellerSimulation.java rename to lowlevel/BankTellerSimulation.java index f9b597c5..c1d81174 100644 --- a/concurrent/BankTellerSimulation.java +++ b/lowlevel/BankTellerSimulation.java @@ -1,4 +1,4 @@ -// concurrent/BankTellerSimulation.java +// lowlevel/BankTellerSimulation.java // (c)2016 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. diff --git a/concurrent/CarBuilder.java b/lowlevel/CarBuilder.java similarity index 99% rename from concurrent/CarBuilder.java rename to lowlevel/CarBuilder.java index 6942158b..91a0ef9a 100644 --- a/concurrent/CarBuilder.java +++ b/lowlevel/CarBuilder.java @@ -1,4 +1,4 @@ -// concurrent/CarBuilder.java +// lowlevel/CarBuilder.java // (c)2016 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. diff --git a/concurrent/Restaurant.java b/lowlevel/Restaurant.java similarity index 98% rename from concurrent/Restaurant.java rename to lowlevel/Restaurant.java index bc8c11e2..d2c6c755 100644 --- a/concurrent/Restaurant.java +++ b/lowlevel/Restaurant.java @@ -1,4 +1,4 @@ -// concurrent/Restaurant.java +// lowlevel/Restaurant.java // (c)2016 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. diff --git a/concurrent/ToastOMatic.java b/lowlevel/ToastOMatic.java similarity index 99% rename from concurrent/ToastOMatic.java rename to lowlevel/ToastOMatic.java index a27f8820..1173a811 100644 --- a/concurrent/ToastOMatic.java +++ b/lowlevel/ToastOMatic.java @@ -1,4 +1,4 @@ -// concurrent/ToastOMatic.java +// lowlevel/ToastOMatic.java // (c)2016 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. diff --git a/concurrent/restaurant2/RestaurantWithQueues.java b/lowlevel/restaurant2/RestaurantWithQueues.java similarity index 99% rename from concurrent/restaurant2/RestaurantWithQueues.java rename to lowlevel/restaurant2/RestaurantWithQueues.java index 8cc184f7..5f75dcd4 100644 --- a/concurrent/restaurant2/RestaurantWithQueues.java +++ b/lowlevel/restaurant2/RestaurantWithQueues.java @@ -1,4 +1,4 @@ -// concurrent/restaurant2/RestaurantWithQueues.java +// lowlevel/restaurant2/RestaurantWithQueues.java // (c)2016 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information.