205 lines
5.0 KiB
Java
205 lines
5.0 KiB
Java
// threads/ToastOMatic.java
|
|
// (c)2016 MindView LLC: see Copyright.txt
|
|
// We make no guarantees that this code is fit for any purpose.
|
|
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
|
|
// A toaster that uses queues
|
|
import java.util.concurrent.*;
|
|
import java.util.*;
|
|
|
|
class Toast {
|
|
public enum Status { DRY, BUTTERED, JAMMED }
|
|
private Status status = Status.DRY;
|
|
private final int id;
|
|
public Toast(int idn) { id = idn; }
|
|
public void butter() { status = Status.BUTTERED; }
|
|
public void jam() { status = Status.JAMMED; }
|
|
public Status getStatus() { return status; }
|
|
public int getId() { return id; }
|
|
@Override
|
|
public String toString() {
|
|
return "Toast " + id + ": " + status;
|
|
}
|
|
}
|
|
|
|
class ToastQueue extends LinkedBlockingQueue<Toast> {}
|
|
|
|
class Toaster implements Runnable {
|
|
private ToastQueue toastQueue;
|
|
private int count = 0;
|
|
private SplittableRandom rand = new SplittableRandom(47);
|
|
public Toaster(ToastQueue tq) { toastQueue = tq; }
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
while(!Thread.interrupted()) {
|
|
TimeUnit.MILLISECONDS.sleep(
|
|
100 + rand.nextInt(500));
|
|
// Make toast
|
|
Toast t = new Toast(count++);
|
|
System.out.println(t);
|
|
// Insert into queue
|
|
toastQueue.put(t);
|
|
}
|
|
} catch(InterruptedException e) {
|
|
System.out.println("Toaster interrupted");
|
|
}
|
|
System.out.println("Toaster off");
|
|
}
|
|
}
|
|
|
|
// Apply butter to toast:
|
|
class Butterer implements Runnable {
|
|
private ToastQueue dryQueue, butteredQueue;
|
|
public Butterer(ToastQueue dry, ToastQueue buttered) {
|
|
dryQueue = dry;
|
|
butteredQueue = buttered;
|
|
}
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
while(!Thread.interrupted()) {
|
|
// Blocks until next piece of toast is available:
|
|
Toast t = dryQueue.take();
|
|
t.butter();
|
|
System.out.println(t);
|
|
butteredQueue.put(t);
|
|
}
|
|
} catch(InterruptedException e) {
|
|
System.out.println("Butterer interrupted");
|
|
}
|
|
System.out.println("Butterer off");
|
|
}
|
|
}
|
|
|
|
// Apply jam to buttered toast:
|
|
class Jammer implements Runnable {
|
|
private ToastQueue butteredQueue, finishedQueue;
|
|
public
|
|
Jammer(ToastQueue buttered, ToastQueue finished) {
|
|
butteredQueue = buttered;
|
|
finishedQueue = finished;
|
|
}
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
while(!Thread.interrupted()) {
|
|
// Blocks until next piece of toast is available:
|
|
Toast t = butteredQueue.take();
|
|
t.jam();
|
|
System.out.println(t);
|
|
finishedQueue.put(t);
|
|
}
|
|
} catch(InterruptedException e) {
|
|
System.out.println("Jammer interrupted");
|
|
}
|
|
System.out.println("Jammer off");
|
|
}
|
|
}
|
|
|
|
// Consume the toast:
|
|
class Eater implements Runnable {
|
|
private ToastQueue finishedQueue;
|
|
private int counter = 0;
|
|
public Eater(ToastQueue finished) {
|
|
finishedQueue = finished;
|
|
}
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
while(!Thread.interrupted()) {
|
|
// Blocks until next piece of toast is available:
|
|
Toast t = finishedQueue.take();
|
|
// Verify that the toast is coming in order,
|
|
// and that all pieces are getting jammed:
|
|
if(t.getId() != counter++ ||
|
|
t.getStatus() != Toast.Status.JAMMED) {
|
|
System.out.println(">>>> Error: " + t);
|
|
System.exit(1);
|
|
} else
|
|
System.out.println("Chomp! " + t);
|
|
}
|
|
} catch(InterruptedException e) {
|
|
System.out.println("Eater interrupted");
|
|
}
|
|
System.out.println("Eater off");
|
|
}
|
|
}
|
|
|
|
public class ToastOMatic {
|
|
public static void
|
|
main(String[] args) throws Exception {
|
|
ToastQueue dryQueue = new ToastQueue(),
|
|
butteredQueue = new ToastQueue(),
|
|
finishedQueue = new ToastQueue();
|
|
ExecutorService es = Executors.newCachedThreadPool();
|
|
es.execute(new Toaster(dryQueue));
|
|
es.execute(new Butterer(dryQueue, butteredQueue));
|
|
es.execute(new Jammer(butteredQueue, finishedQueue));
|
|
es.execute(new Eater(finishedQueue));
|
|
TimeUnit.SECONDS.sleep(5);
|
|
es.shutdownNow();
|
|
}
|
|
}
|
|
/* Output:
|
|
Toast 0: DRY
|
|
Toast 0: BUTTERED
|
|
Toast 0: JAMMED
|
|
Chomp! Toast 0: JAMMED
|
|
Toast 1: DRY
|
|
Toast 1: BUTTERED
|
|
Toast 1: JAMMED
|
|
Chomp! Toast 1: JAMMED
|
|
Toast 2: DRY
|
|
Toast 2: BUTTERED
|
|
Toast 2: JAMMED
|
|
Chomp! Toast 2: JAMMED
|
|
Toast 3: DRY
|
|
Toast 3: BUTTERED
|
|
Toast 3: JAMMED
|
|
Chomp! Toast 3: JAMMED
|
|
Toast 4: DRY
|
|
Toast 4: BUTTERED
|
|
Toast 4: JAMMED
|
|
Chomp! Toast 4: JAMMED
|
|
Toast 5: DRY
|
|
Toast 5: BUTTERED
|
|
Toast 5: JAMMED
|
|
Chomp! Toast 5: JAMMED
|
|
Toast 6: DRY
|
|
Toast 6: BUTTERED
|
|
Toast 6: JAMMED
|
|
Chomp! Toast 6: JAMMED
|
|
Toast 7: DRY
|
|
Toast 7: BUTTERED
|
|
Toast 7: JAMMED
|
|
Chomp! Toast 7: JAMMED
|
|
Toast 8: DRY
|
|
Toast 8: BUTTERED
|
|
Toast 8: JAMMED
|
|
Chomp! Toast 8: JAMMED
|
|
Toast 9: DRY
|
|
Toast 9: BUTTERED
|
|
Toast 9: JAMMED
|
|
Chomp! Toast 9: JAMMED
|
|
Toast 10: DRY
|
|
Toast 10: BUTTERED
|
|
Toast 10: JAMMED
|
|
Chomp! Toast 10: JAMMED
|
|
Toast 11: DRY
|
|
Toast 11: BUTTERED
|
|
Toast 11: JAMMED
|
|
Chomp! Toast 11: JAMMED
|
|
Toast 12: DRY
|
|
Toast 12: BUTTERED
|
|
Toast 12: JAMMED
|
|
Chomp! Toast 12: JAMMED
|
|
Eater interrupted
|
|
Eater off
|
|
Jammer interrupted
|
|
Jammer off
|
|
Toaster interrupted
|
|
Butterer interrupted
|
|
Butterer off
|
|
Toaster off
|
|
*/
|