Appendix rewrites

This commit is contained in:
Bruce Eckel 2017-01-12 16:49:36 -08:00
parent bc786ef438
commit 737320b37b
14 changed files with 148 additions and 158 deletions

View File

@ -3,7 +3,6 @@
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
// Atomic classes are occasionally useful in regular code // Atomic classes are occasionally useful in regular code
// {IgnoreOutput} // No output validation
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
public class AtomicEvenProducer extends IntGenerator { public class AtomicEvenProducer extends IntGenerator {
@ -17,3 +16,6 @@ public class AtomicEvenProducer extends IntGenerator {
EvenChecker.test(new AtomicEvenProducer()); EvenChecker.test(new AtomicEvenProducer());
} }
} }
/* Output:
No odd numbers discovered
*/

View File

@ -17,11 +17,9 @@ public class AtomicIntegerTest implements Runnable {
evenIncrement(); evenIncrement();
} }
public static void main(String[] args) { public static void main(String[] args) {
new TimedAbort(5); // Terminate after 5 seconds new TimedAbort(4, "No failures discovered");
ExecutorService exec =
Executors.newCachedThreadPool();
AtomicIntegerTest ait = new AtomicIntegerTest(); AtomicIntegerTest ait = new AtomicIntegerTest();
exec.execute(ait); CompletableFuture.runAsync(ait);
while(true) { while(true) {
int val = ait.getValue(); int val = ait.getValue();
if(val % 2 != 0) { if(val % 2 != 0) {
@ -32,5 +30,5 @@ public class AtomicIntegerTest implements Runnable {
} }
} }
/* Output: /* Output:
TimedAbort 5 No failures discovered
*/ */

View File

@ -13,29 +13,32 @@ public class Atomicity {
Compiled from "Atomicity.java" Compiled from "Atomicity.java"
public class Atomicity { public class Atomicity {
int i; int i;
public Atomicity(); public Atomicity();
Code: Code:
0: aload_0 0: aload_0
1: invokespecial #1 // Method 1: invokespecial #1 // Method
java/lang/Object."<init>":()V java/lang/Object."<init>":()V
4: return 4: return
void f1(); void f1();
Code: Code:
0: aload_0 0: aload_0
1: dup 1: dup
2: getfield #2 // Field i:I 2: getfield #2 // Field i:I
5: iconst_1 5: iconst_1
6: iadd 6: iadd
7: putfield #2 // Field i:I 7: putfield #2 // Field i:I
10: return 10: return
void f2(); void f2();
Code: Code:
0: aload_0 0: aload_0
1: dup 1: dup
2: getfield #2 // Field i:I 2: getfield #2 // Field i:I
5: iconst_3 5: iconst_3
6: iadd 6: iadd
7: putfield #2 // Field i:I 7: putfield #2 // Field i:I
10: return 10: return
} }
*/ */

View File

@ -17,20 +17,18 @@ public class AtomicityTest implements Runnable {
evenIncrement(); evenIncrement();
} }
public static void main(String[] args) { public static void main(String[] args) {
new TimedAbort(4); new TimedAbort(4, "No failures found");
ExecutorService es =
Executors.newCachedThreadPool();
AtomicityTest at = new AtomicityTest(); AtomicityTest at = new AtomicityTest();
es.execute(at); CompletableFuture.runAsync(at);
while(true) { while(true) {
int val = at.getValue(); int val = at.getValue();
if(val % 2 != 0) { if(val % 2 != 0) {
System.out.println(val); System.out.println("failed with: " + val);
System.exit(0); System.exit(0);
} }
} }
} }
} }
/* Output: /* Output:
1 failed with: 21
*/ */

View File

@ -38,16 +38,12 @@ public class AttemptLocking {
final AttemptLocking al = new AttemptLocking(); final AttemptLocking al = new AttemptLocking();
al.untimed(); // True -- lock is available al.untimed(); // True -- lock is available
al.timed(); // True -- lock is available al.timed(); // True -- lock is available
// Now create a separate task to grab the lock: // Now create a second task to grab the lock:
new Thread() { CompletableFuture.runAsync( () -> {
{ setDaemon(true); }
@Override
public void run() {
al.lock.lock(); al.lock.lock();
System.out.println("acquired"); System.out.println("acquired");
} });
}.start(); new Nap(100); // Give the second task a chance
new Nap(10); // Give the 2nd task a chance
al.untimed(); // False -- lock grabbed by task al.untimed(); // False -- lock grabbed by task
al.timed(); // False -- lock grabbed by task al.timed(); // False -- lock grabbed by task
} }
@ -55,6 +51,7 @@ public class AttemptLocking {
/* Output: /* Output:
tryLock(): true tryLock(): true
tryLock(2, TimeUnit.SECONDS): true tryLock(2, TimeUnit.SECONDS): true
tryLock(): true acquired
tryLock(2, TimeUnit.SECONDS): true tryLock(): false
tryLock(2, TimeUnit.SECONDS): false
*/ */

View File

@ -2,8 +2,9 @@
// (c)2017 MindView LLC: see Copyright.txt // (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
import java.util.concurrent.*;
import java.util.*; import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*;
import static java.util.concurrent.TimeUnit.*; import static java.util.concurrent.TimeUnit.*;
class DelayedTask implements Runnable, Delayed { class DelayedTask implements Runnable, Delayed {
@ -12,7 +13,7 @@ class DelayedTask implements Runnable, Delayed {
private final int delta; private final int delta;
private final long trigger; private final long trigger;
protected static List<DelayedTask> sequence = protected static List<DelayedTask> sequence =
new ArrayList<>(); new CopyOnWriteArrayList<>();
public DelayedTask(int delayInMilliseconds) { public DelayedTask(int delayInMilliseconds) {
delta = delayInMilliseconds; delta = delayInMilliseconds;
trigger = System.nanoTime() + trigger = System.nanoTime() +
@ -32,74 +33,69 @@ class DelayedTask implements Runnable, Delayed {
return 0; return 0;
} }
@Override @Override
public void run() { System.out.print(this + " "); } public void run() {
System.out.print(this + " ");
}
@Override @Override
public String toString() { public String toString() {
return String.format("[%1$-4d]", delta) + return
" Task " + id; String.format("[%d] Task %d", delta, id);
} }
public String summary() { public String summary() {
return "(" + id + ":" + delta + ")"; return String.format("(%d:%d)", id, delta);
} }
public static class EndSentinel extends DelayedTask { public static class EndTask extends DelayedTask {
private ExecutorService exec; public EndTask(int delay) { super(delay); }
public EndSentinel(int delay, ExecutorService e) {
super(delay);
exec = e;
}
@Override @Override
public void run() { public void run() {
for(DelayedTask pt : sequence) { sequence.forEach(dt ->
System.out.print(pt.summary() + " "); System.out.println(dt.summary() + " "));
}
System.out.println();
System.out.println(this + " Calling shutdownNow()");
exec.shutdownNow();
} }
} }
} }
class DelayedTaskConsumer implements Runnable {
private DelayQueue<DelayedTask> q;
public DelayedTaskConsumer(DelayQueue<DelayedTask> 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 class DelayQueueDemo {
public static void main(String[] args) { public static void
SplittableRandom rand = new SplittableRandom(47); main(String[] args) throws Exception {
ExecutorService es = Executors.newCachedThreadPool(); DelayQueue<DelayedTask> tasks =
DelayQueue<DelayedTask> queue = Stream.concat(
new DelayQueue<>(); // Tasks with random delays:
// Fill with tasks that have random delays: new Random(47).ints(20, 0, 4000)
for(int i = 0; i < 20; i++) .mapToObj(DelayedTask::new),
queue.put(new DelayedTask(rand.nextInt(5000))); // Add the summarizing task:
// Set the stopping point Stream.of(
queue.add(new DelayedTask.EndSentinel(5000, es)); new DelayedTask.EndTask(4000)))
es.execute(new DelayedTaskConsumer(queue)); .collect(Collectors
.toCollection(DelayQueue::new));
DelayQueue<DelayedTask> delayQueue =
new DelayQueue<>(tasks);
while(delayQueue.size() > 0)
delayQueue.take().run();
} }
} }
/* Output: /* Output:
[70 ] Task 10 [125 ] Task 13 [267 ] Task 19 [635 ] Task 0 [128] Task 12 [429] Task 6 [551] Task 13 [555] Task 2 [693] Task 3 [809] Task 15
[650 ] Task 16 [682 ] Task 17 [807 ] Task 11 [1131] Task 18 [961] Task 5 [1258] Task 1 [1258] Task 20 [1520] Task 19 [1861] Task 4 [1998] T
[1177] Task 4 [1193] Task 9 [1634] Task 15 [1656] Task 6 ask 17 [2200] Task 8 [2207] Task 10 [2288] Task 11 [2522] Task 9 [2589] Task 14
[2400] Task 12 [3479] Task 5 [3737] Task 1 [3768] Task 7 [2861] Task 18 [2868] Task 7 [3278] Task 16 (0:4000)
[3941] Task 2 [4720] Task 3 [4762] Task 14 [4948] Task 8 (1:1258)
(0:635) (1:3737) (2:3941) (3:4720) (4:1177) (5:3479) (2:555)
(6:1656) (7:3768) (8:4948) (9:1193) (10:70) (11:807) (3:693)
(12:2400) (13:125) (14:4762) (15:1634) (16:650) (17:682) (4:1861)
(18:1131) (19:267) (20:5000) (5:961)
[5000] Task 20 Calling shutdownNow() (6:429)
Finished DelayedTaskConsumer (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)
*/ */

View File

@ -2,6 +2,8 @@
// (c)2017 MindView LLC: see Copyright.txt // (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import onjava.TimedAbort; import onjava.TimedAbort;
@ -24,15 +26,16 @@ public class EvenChecker implements Runnable {
} }
// Test any IntGenerator: // Test any IntGenerator:
public static void test(IntGenerator gp, int count) { public static void test(IntGenerator gp, int count) {
System.out.println("Press Control-C to exit"); List<CompletableFuture<Void>> checkers =
ExecutorService es = Executors.newCachedThreadPool(); IntStream.range(0, count)
for(int i = 0; i < count; i++) .mapToObj(i -> new EvenChecker(gp, i))
es.execute(new EvenChecker(gp, i)); .map(CompletableFuture::runAsync)
es.shutdown(); .collect(Collectors.toList());
checkers.forEach(CompletableFuture::join);
} }
// Default value for count: // Default value for count:
public static void test(IntGenerator gp) { public static void test(IntGenerator gp) {
new TimedAbort(4); new TimedAbort(4, "No odd numbers discovered");
test(gp, 10); test(gp, 10);
} }
} }

View File

@ -17,9 +17,10 @@ public class EvenProducer extends IntGenerator {
} }
} }
/* Output: /* Output:
Press Control-C to exit 1563 not even!
841 not even! 1573 not even!
847 not even! 1571 not even!
845 not even! 1569 not even!
843 not even! 1567 not even!
1565 not even!
*/ */

View File

@ -3,7 +3,6 @@
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
// Preventing thread collisions with mutexes // Preventing thread collisions with mutexes
// {IgnoreOutput} // No output validation
import java.util.concurrent.locks.*; import java.util.concurrent.locks.*;
import onjava.Nap; import onjava.Nap;
@ -26,3 +25,6 @@ public class MutexEvenProducer extends IntGenerator {
EvenChecker.test(new MutexEvenProducer()); EvenChecker.test(new MutexEvenProducer());
} }
} }
/*
No odd numbers discovered
*/

View File

@ -3,65 +3,54 @@
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
// Operations that might seem safe are not, // Operations that might seem safe are not,
// when threads are present // when threads are present.
// {java SerialNumberChecker 4} import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import onjava.Nap; import onjava.Nap;
// Reuses storage so we don't run out of memory: // Reuses storage so we don't run out of memory:
class CircularSet { class CircularSet {
private int[] array; private int[] array;
private int len; private int size;
private int index = 0; private int index = 0;
public CircularSet(int size) { public CircularSet(int size) {
array = new int[size]; array = new int[size];
len = size;
// Initialize to a value not produced // Initialize to a value not produced
// by the SerialNumberSupplier: // by the SerialNumberSupplier:
for(int i = 0; i < size; i++) Arrays.fill(array, -1);
array[i] = -1; this.size = size;
} }
public synchronized void add(int i) { public synchronized void add(int i) {
array[index] = i; array[index] = i;
// Wrap index and write over old elements: // Wrap index and write over old elements:
index = ++index % len; index = ++index % size;
} }
public synchronized boolean contains(int val) { 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; if(array[i] == val) return true;
return false; return false;
} }
} }
public class SerialNumberChecker { public class SerialNumberChecker implements Runnable {
private static final int SIZE = 10; private CircularSet serials = new CircularSet(1000);
private static CircularSet serials = @Override
new CircularSet(1000); public void run() {
private static ExecutorService exec = while(true) {
Executors.newCachedThreadPool(); int serial =
static class SerialChecker implements Runnable { SerialNumberSupplier.nextSerialNumber();
@Override if(serials.contains(serial)) {
public void run() { System.out.println("Duplicate: " + serial);
while(true) { System.exit(0);
int serial =
SerialNumberSupplier.nextSerialNumber();
if(serials.contains(serial)) {
System.out.println("Duplicate: " + serial);
System.exit(0);
}
serials.add(serial);
} }
serials.add(serial);
} }
} }
public static void main(String[] args) { public static void main(String[] args) {
for(int i = 0; i < SIZE; i++) for(int i = 0; i < 10; i++)
exec.execute(new SerialChecker()); CompletableFuture.runAsync(
// Stop after n seconds if there's an argument: new SerialNumberChecker());
if(args.length > 0) { new Nap(4000, "No duplicates detected");
new Nap(new Integer(args[0]) * 1000);
System.out.println("No duplicates detected");
System.exit(0);
}
} }
} }
/* Output: /* Output:

View File

@ -3,47 +3,39 @@
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
// Synchronizing on another object // Synchronizing on another object
import java.util.concurrent.*;
import onjava.Nap; import onjava.Nap;
class DualSynch { class DualSynch {
private Object syncObject = new Object();
public synchronized void f() { public synchronized void f() {
for(int i = 0; i < 5; i++) { for(int i = 0; i < 5; i++)
System.out.println("f()"); System.out.println("f() " + i);
new Nap(10);
}
} }
private Object syncObject = new Object();
public void g() { public void g() {
synchronized(syncObject) { synchronized(syncObject) {
for(int i = 0; i < 5; i++) { for(int i = 0; i < 5; i++)
System.out.println("g()"); System.out.println("g() " + i);
new Nap(10);
}
} }
} }
} }
public class SyncObject { public class SyncObject {
public static void main(String[] args) { public static void main(String[] args) {
final DualSynch ds = new DualSynch(); DualSynch ds = new DualSynch();
new Thread() { CompletableFuture.runAsync(() -> ds.f());
@Override
public void run() {
ds.f();
}
}.start();
ds.g(); ds.g();
} }
} }
/* Output: /* Output:
g() g() 0
g() g() 1
g() f() 0
g() g() 2
g() f() 1
f() g() 3
f() f() 2
f() g() 4
f() f() 3
f() f() 4
*/ */

View File

@ -3,7 +3,6 @@
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
// Simplifying mutexes with the synchronized keyword // Simplifying mutexes with the synchronized keyword
// {IgnoreOutput} // No output validation
import onjava.Nap; import onjava.Nap;
public class public class
@ -20,3 +19,6 @@ SynchronizedEvenProducer extends IntGenerator {
EvenChecker.test(new SynchronizedEvenProducer()); EvenChecker.test(new SynchronizedEvenProducer());
} }
} }
/* Output:
No odd numbers discovered
*/

View File

@ -14,4 +14,8 @@ public class Nap {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public Nap(int n, String msg) {
this(n);
System.out.println(msg);
}
} }

View File

@ -7,11 +7,14 @@ package onjava;
import java.util.concurrent.*; import java.util.concurrent.*;
public class TimedAbort { public class TimedAbort {
public TimedAbort(int n) { public TimedAbort(int n, String msg) {
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
new Nap(1000 * n); new Nap(1000 * n);
System.out.println("TimedAbort " + n); System.out.println(msg);
System.exit(0); System.exit(0);
}); });
} }
public TimedAbort(int n) {
this(n, "TimedAbort " + n);
}
} }