diff --git a/lowlevel/AtomicEvenProducer.java b/lowlevel/AtomicEvenProducer.java index d4a62605..a965e001 100644 --- a/lowlevel/AtomicEvenProducer.java +++ b/lowlevel/AtomicEvenProducer.java @@ -3,7 +3,6 @@ // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. // Atomic classes are occasionally useful in regular code -// {IgnoreOutput} // No output validation import java.util.concurrent.atomic.*; public class AtomicEvenProducer extends IntGenerator { @@ -17,3 +16,6 @@ public class AtomicEvenProducer extends IntGenerator { EvenChecker.test(new AtomicEvenProducer()); } } +/* Output: +No odd numbers discovered +*/ diff --git a/lowlevel/AtomicIntegerTest.java b/lowlevel/AtomicIntegerTest.java index f9f3bc26..9c372350 100644 --- a/lowlevel/AtomicIntegerTest.java +++ b/lowlevel/AtomicIntegerTest.java @@ -17,11 +17,9 @@ public class AtomicIntegerTest implements Runnable { evenIncrement(); } public static void main(String[] args) { - new TimedAbort(5); // Terminate after 5 seconds - ExecutorService exec = - Executors.newCachedThreadPool(); + new TimedAbort(4, "No failures discovered"); AtomicIntegerTest ait = new AtomicIntegerTest(); - exec.execute(ait); + CompletableFuture.runAsync(ait); while(true) { int val = ait.getValue(); if(val % 2 != 0) { @@ -32,5 +30,5 @@ public class AtomicIntegerTest implements Runnable { } } /* Output: -TimedAbort 5 +No failures discovered */ diff --git a/lowlevel/Atomicity.java b/lowlevel/Atomicity.java index ea4a5e20..19c73c8a 100644 --- a/lowlevel/Atomicity.java +++ b/lowlevel/Atomicity.java @@ -13,29 +13,32 @@ public class Atomicity { Compiled from "Atomicity.java" public class Atomicity { int i; + public Atomicity(); Code: 0: aload_0 - 1: invokespecial #1 // Method + 1: invokespecial #1 // Method java/lang/Object."":()V 4: return + void f1(); Code: 0: aload_0 1: dup - 2: getfield #2 // Field i:I + 2: getfield #2 // Field i:I 5: iconst_1 6: iadd - 7: putfield #2 // Field i:I + 7: putfield #2 // Field i:I 10: return + void f2(); Code: 0: aload_0 1: dup - 2: getfield #2 // Field i:I + 2: getfield #2 // Field i:I 5: iconst_3 6: iadd - 7: putfield #2 // Field i:I + 7: putfield #2 // Field i:I 10: return } */ diff --git a/lowlevel/AtomicityTest.java b/lowlevel/AtomicityTest.java index 0174f961..53acd2b8 100644 --- a/lowlevel/AtomicityTest.java +++ b/lowlevel/AtomicityTest.java @@ -17,20 +17,18 @@ public class AtomicityTest implements Runnable { evenIncrement(); } public static void main(String[] args) { - new TimedAbort(4); - ExecutorService es = - Executors.newCachedThreadPool(); + new TimedAbort(4, "No failures found"); AtomicityTest at = new AtomicityTest(); - es.execute(at); + CompletableFuture.runAsync(at); while(true) { int val = at.getValue(); if(val % 2 != 0) { - System.out.println(val); + System.out.println("failed with: " + val); System.exit(0); } } } } /* Output: -1 +failed with: 21 */ diff --git a/lowlevel/AttemptLocking.java b/lowlevel/AttemptLocking.java index 64d79ee6..510b5e52 100644 --- a/lowlevel/AttemptLocking.java +++ b/lowlevel/AttemptLocking.java @@ -38,16 +38,12 @@ public class AttemptLocking { final AttemptLocking al = new AttemptLocking(); al.untimed(); // True -- lock is available al.timed(); // True -- lock is available - // Now create a separate task to grab the lock: - new Thread() { - { setDaemon(true); } - @Override - public void run() { + // Now create a second task to grab the lock: + CompletableFuture.runAsync( () -> { al.lock.lock(); System.out.println("acquired"); - } - }.start(); - new Nap(10); // Give the 2nd task a chance + }); + new Nap(100); // Give the second task a chance al.untimed(); // False -- lock grabbed by task al.timed(); // False -- lock grabbed by task } @@ -55,6 +51,7 @@ public class AttemptLocking { /* Output: tryLock(): true tryLock(2, TimeUnit.SECONDS): true -tryLock(): true -tryLock(2, TimeUnit.SECONDS): true +acquired +tryLock(): false +tryLock(2, TimeUnit.SECONDS): false */ diff --git a/lowlevel/DelayQueueDemo.java b/lowlevel/DelayQueueDemo.java index d76e22f0..4fc0bba2 100644 --- a/lowlevel/DelayQueueDemo.java +++ b/lowlevel/DelayQueueDemo.java @@ -2,8 +2,9 @@ // (c)2017 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.*; +import java.util.stream.*; +import java.util.concurrent.*; import static java.util.concurrent.TimeUnit.*; class DelayedTask implements Runnable, Delayed { @@ -12,7 +13,7 @@ class DelayedTask implements Runnable, Delayed { private final int delta; private final long trigger; protected static List sequence = - new ArrayList<>(); + new CopyOnWriteArrayList<>(); public DelayedTask(int delayInMilliseconds) { delta = delayInMilliseconds; trigger = System.nanoTime() + @@ -32,74 +33,69 @@ class DelayedTask implements Runnable, Delayed { return 0; } @Override - public void run() { System.out.print(this + " "); } + public void run() { + System.out.print(this + " "); + } @Override public String toString() { - return String.format("[%1$-4d]", delta) + - " Task " + id; + return + String.format("[%d] Task %d", delta, id); } public String summary() { - return "(" + id + ":" + delta + ")"; + return String.format("(%d:%d)", id, delta); } - public static class EndSentinel extends DelayedTask { - private ExecutorService exec; - public EndSentinel(int delay, ExecutorService e) { - super(delay); - exec = e; - } + public static class EndTask extends DelayedTask { + public EndTask(int delay) { super(delay); } @Override public void run() { - for(DelayedTask pt : sequence) { - System.out.print(pt.summary() + " "); - } - System.out.println(); - System.out.println(this + " Calling shutdownNow()"); - exec.shutdownNow(); + sequence.forEach(dt -> + System.out.println(dt.summary() + " ")); } } } -class DelayedTaskConsumer implements Runnable { - private DelayQueue q; - public DelayedTaskConsumer(DelayQueue q) { - this.q = q; - } - @Override - public void run() { - try { - while(!Thread.interrupted()) - q.take().run(); // Run task with current thread - } catch(InterruptedException e) { - // Acceptable way to exit - } - System.out.println("Finished DelayedTaskConsumer"); - } -} - public class DelayQueueDemo { - public static void main(String[] args) { - SplittableRandom rand = new SplittableRandom(47); - ExecutorService es = Executors.newCachedThreadPool(); - DelayQueue queue = - new DelayQueue<>(); - // Fill with tasks that have random delays: - for(int i = 0; i < 20; i++) - queue.put(new DelayedTask(rand.nextInt(5000))); - // Set the stopping point - queue.add(new DelayedTask.EndSentinel(5000, es)); - es.execute(new DelayedTaskConsumer(queue)); + public static void + main(String[] args) throws Exception { + DelayQueue tasks = + Stream.concat( + // Tasks with random delays: + new Random(47).ints(20, 0, 4000) + .mapToObj(DelayedTask::new), + // Add the summarizing task: + Stream.of( + new DelayedTask.EndTask(4000))) + .collect(Collectors + .toCollection(DelayQueue::new)); + DelayQueue delayQueue = + new DelayQueue<>(tasks); + while(delayQueue.size() > 0) + delayQueue.take().run(); } } /* Output: -[70 ] Task 10 [125 ] Task 13 [267 ] Task 19 [635 ] Task 0 -[650 ] Task 16 [682 ] Task 17 [807 ] Task 11 [1131] Task 18 -[1177] Task 4 [1193] Task 9 [1634] Task 15 [1656] Task 6 -[2400] Task 12 [3479] Task 5 [3737] Task 1 [3768] Task 7 -[3941] Task 2 [4720] Task 3 [4762] Task 14 [4948] Task 8 -(0:635) (1:3737) (2:3941) (3:4720) (4:1177) (5:3479) -(6:1656) (7:3768) (8:4948) (9:1193) (10:70) (11:807) -(12:2400) (13:125) (14:4762) (15:1634) (16:650) (17:682) -(18:1131) (19:267) (20:5000) -[5000] Task 20 Calling shutdownNow() -Finished DelayedTaskConsumer +[128] Task 12 [429] Task 6 [551] Task 13 [555] Task 2 [693] Task 3 [809] Task 15 + [961] Task 5 [1258] Task 1 [1258] Task 20 [1520] Task 19 [1861] Task 4 [1998] T +ask 17 [2200] Task 8 [2207] Task 10 [2288] Task 11 [2522] Task 9 [2589] Task 14 +[2861] Task 18 [2868] Task 7 [3278] Task 16 (0:4000) +(1:1258) +(2:555) +(3:693) +(4:1861) +(5:961) +(6:429) +(7:2868) +(8:2200) +(9:2522) +(10:2207) +(11:2288) +(12:128) +(13:551) +(14:2589) +(15:809) +(16:3278) +(17:1998) +(18:2861) +(19:1520) +(20:1258) */ diff --git a/lowlevel/EvenChecker.java b/lowlevel/EvenChecker.java index 2a1e958c..75c89e0f 100644 --- a/lowlevel/EvenChecker.java +++ b/lowlevel/EvenChecker.java @@ -2,6 +2,8 @@ // (c)2017 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 java.util.stream.*; import java.util.concurrent.*; import onjava.TimedAbort; @@ -24,15 +26,16 @@ public class EvenChecker implements Runnable { } // Test any IntGenerator: public static void test(IntGenerator gp, int count) { - System.out.println("Press Control-C to exit"); - ExecutorService es = Executors.newCachedThreadPool(); - for(int i = 0; i < count; i++) - es.execute(new EvenChecker(gp, i)); - es.shutdown(); + List> checkers = + IntStream.range(0, count) + .mapToObj(i -> new EvenChecker(gp, i)) + .map(CompletableFuture::runAsync) + .collect(Collectors.toList()); + checkers.forEach(CompletableFuture::join); } // Default value for count: public static void test(IntGenerator gp) { - new TimedAbort(4); + new TimedAbort(4, "No odd numbers discovered"); test(gp, 10); } } diff --git a/lowlevel/EvenProducer.java b/lowlevel/EvenProducer.java index c274ad09..d51ec838 100644 --- a/lowlevel/EvenProducer.java +++ b/lowlevel/EvenProducer.java @@ -17,9 +17,10 @@ public class EvenProducer extends IntGenerator { } } /* Output: -Press Control-C to exit -841 not even! -847 not even! -845 not even! -843 not even! +1563 not even! +1573 not even! +1571 not even! +1569 not even! +1567 not even! +1565 not even! */ diff --git a/lowlevel/MutexEvenProducer.java b/lowlevel/MutexEvenProducer.java index ab1244b0..999d0ed0 100644 --- a/lowlevel/MutexEvenProducer.java +++ b/lowlevel/MutexEvenProducer.java @@ -3,7 +3,6 @@ // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. // Preventing thread collisions with mutexes -// {IgnoreOutput} // No output validation import java.util.concurrent.locks.*; import onjava.Nap; @@ -26,3 +25,6 @@ public class MutexEvenProducer extends IntGenerator { EvenChecker.test(new MutexEvenProducer()); } } +/* +No odd numbers discovered +*/ diff --git a/lowlevel/SerialNumberChecker.java b/lowlevel/SerialNumberChecker.java index a04677b4..09ef4235 100644 --- a/lowlevel/SerialNumberChecker.java +++ b/lowlevel/SerialNumberChecker.java @@ -3,65 +3,54 @@ // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. // Operations that might seem safe are not, -// when threads are present -// {java SerialNumberChecker 4} +// when threads are present. +import java.util.*; import java.util.concurrent.*; import onjava.Nap; // Reuses storage so we don't run out of memory: class CircularSet { private int[] array; - private int len; + private int size; private int index = 0; public CircularSet(int size) { array = new int[size]; - len = size; // Initialize to a value not produced // by the SerialNumberSupplier: - for(int i = 0; i < size; i++) - array[i] = -1; + Arrays.fill(array, -1); + this.size = size; } public synchronized void add(int i) { array[index] = i; // Wrap index and write over old elements: - index = ++index % len; + index = ++index % size; } public synchronized boolean contains(int val) { - for(int i = 0; i < len; i++) + for(int i = 0; i < size; i++) if(array[i] == val) return true; return false; } } -public class SerialNumberChecker { - private static final int SIZE = 10; - private static CircularSet serials = - new CircularSet(1000); - private static ExecutorService exec = - Executors.newCachedThreadPool(); - static class SerialChecker implements Runnable { - @Override - public void run() { - while(true) { - int serial = - SerialNumberSupplier.nextSerialNumber(); - if(serials.contains(serial)) { - System.out.println("Duplicate: " + serial); - System.exit(0); - } - serials.add(serial); +public class SerialNumberChecker implements Runnable { + private CircularSet serials = new CircularSet(1000); + @Override + public void run() { + while(true) { + int serial = + SerialNumberSupplier.nextSerialNumber(); + if(serials.contains(serial)) { + System.out.println("Duplicate: " + serial); + System.exit(0); } + serials.add(serial); } } public static void main(String[] args) { - for(int i = 0; i < SIZE; i++) - exec.execute(new SerialChecker()); - // Stop after n seconds if there's an argument: - if(args.length > 0) { - new Nap(new Integer(args[0]) * 1000); - System.out.println("No duplicates detected"); - System.exit(0); - } + for(int i = 0; i < 10; i++) + CompletableFuture.runAsync( + new SerialNumberChecker()); + new Nap(4000, "No duplicates detected"); } } /* Output: diff --git a/lowlevel/SyncObject.java b/lowlevel/SyncObject.java index ac2c96d9..f5c88352 100644 --- a/lowlevel/SyncObject.java +++ b/lowlevel/SyncObject.java @@ -3,47 +3,39 @@ // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. // Synchronizing on another object +import java.util.concurrent.*; import onjava.Nap; class DualSynch { - private Object syncObject = new Object(); public synchronized void f() { - for(int i = 0; i < 5; i++) { - System.out.println("f()"); - new Nap(10); - } + for(int i = 0; i < 5; i++) + System.out.println("f() " + i); } + private Object syncObject = new Object(); public void g() { synchronized(syncObject) { - for(int i = 0; i < 5; i++) { - System.out.println("g()"); - new Nap(10); - } + for(int i = 0; i < 5; i++) + System.out.println("g() " + i); } } } public class SyncObject { public static void main(String[] args) { - final DualSynch ds = new DualSynch(); - new Thread() { - @Override - public void run() { - ds.f(); - } - }.start(); + DualSynch ds = new DualSynch(); + CompletableFuture.runAsync(() -> ds.f()); ds.g(); } } /* Output: -g() -g() -g() -g() -g() -f() -f() -f() -f() -f() +g() 0 +g() 1 +f() 0 +g() 2 +f() 1 +g() 3 +f() 2 +g() 4 +f() 3 +f() 4 */ diff --git a/lowlevel/SynchronizedEvenProducer.java b/lowlevel/SynchronizedEvenProducer.java index c1bba5f7..0c922f7d 100644 --- a/lowlevel/SynchronizedEvenProducer.java +++ b/lowlevel/SynchronizedEvenProducer.java @@ -3,7 +3,6 @@ // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. // Simplifying mutexes with the synchronized keyword -// {IgnoreOutput} // No output validation import onjava.Nap; public class @@ -20,3 +19,6 @@ SynchronizedEvenProducer extends IntGenerator { EvenChecker.test(new SynchronizedEvenProducer()); } } +/* Output: +No odd numbers discovered +*/ diff --git a/onjava/Nap.java b/onjava/Nap.java index c4a66b4b..13516694 100644 --- a/onjava/Nap.java +++ b/onjava/Nap.java @@ -14,4 +14,8 @@ public class Nap { throw new RuntimeException(e); } } + public Nap(int n, String msg) { + this(n); + System.out.println(msg); + } } diff --git a/onjava/TimedAbort.java b/onjava/TimedAbort.java index 5c5d262c..5de4ac55 100644 --- a/onjava/TimedAbort.java +++ b/onjava/TimedAbort.java @@ -7,11 +7,14 @@ package onjava; import java.util.concurrent.*; public class TimedAbort { - public TimedAbort(int n) { + public TimedAbort(int n, String msg) { CompletableFuture.runAsync(() -> { new Nap(1000 * n); - System.out.println("TimedAbort " + n); + System.out.println(msg); System.exit(0); }); } + public TimedAbort(int n) { + this(n, "TimedAbort " + n); + } }