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.
// 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
*/

View File

@ -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
*/

View File

@ -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."<init>":()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
}
*/

View File

@ -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
*/

View File

@ -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
*/

View File

@ -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<DelayedTask> 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<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 static void main(String[] args) {
SplittableRandom rand = new SplittableRandom(47);
ExecutorService es = Executors.newCachedThreadPool();
DelayQueue<DelayedTask> 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<DelayedTask> 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<DelayedTask> 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)
*/

View File

@ -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<CompletableFuture<Void>> 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);
}
}

View File

@ -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!
*/

View File

@ -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
*/

View File

@ -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:

View File

@ -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
*/

View File

@ -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
*/

View File

@ -14,4 +14,8 @@ public class Nap {
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.*;
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);
}
}