Appendix rewrites
This commit is contained in:
parent
bc786ef438
commit
737320b37b
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
}
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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)
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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!
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -14,4 +14,8 @@ public class Nap {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
public Nap(int n, String msg) {
|
||||
this(n);
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user