134 lines
3.7 KiB
Java
134 lines
3.7 KiB
Java
|
//: concurrency/ToastOMatic.java
|
||
|
// A toaster that uses queues.
|
||
|
import java.util.concurrent.*;
|
||
|
import java.util.*;
|
||
|
import static net.mindview.util.Print.*;
|
||
|
|
||
|
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; }
|
||
|
public String toString() {
|
||
|
return "Toast " + id + ": " + status;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class ToastQueue extends LinkedBlockingQueue<Toast> {}
|
||
|
|
||
|
class Toaster implements Runnable {
|
||
|
private ToastQueue toastQueue;
|
||
|
private int count = 0;
|
||
|
private Random rand = new Random(47);
|
||
|
public Toaster(ToastQueue tq) { toastQueue = tq; }
|
||
|
public void run() {
|
||
|
try {
|
||
|
while(!Thread.interrupted()) {
|
||
|
TimeUnit.MILLISECONDS.sleep(
|
||
|
100 + rand.nextInt(500));
|
||
|
// Make toast
|
||
|
Toast t = new Toast(count++);
|
||
|
print(t);
|
||
|
// Insert into queue
|
||
|
toastQueue.put(t);
|
||
|
}
|
||
|
} catch(InterruptedException e) {
|
||
|
print("Toaster interrupted");
|
||
|
}
|
||
|
print("Toaster off");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Apply butter to toast:
|
||
|
class Butterer implements Runnable {
|
||
|
private ToastQueue dryQueue, butteredQueue;
|
||
|
public Butterer(ToastQueue dry, ToastQueue buttered) {
|
||
|
dryQueue = dry;
|
||
|
butteredQueue = buttered;
|
||
|
}
|
||
|
public void run() {
|
||
|
try {
|
||
|
while(!Thread.interrupted()) {
|
||
|
// Blocks until next piece of toast is available:
|
||
|
Toast t = dryQueue.take();
|
||
|
t.butter();
|
||
|
print(t);
|
||
|
butteredQueue.put(t);
|
||
|
}
|
||
|
} catch(InterruptedException e) {
|
||
|
print("Butterer interrupted");
|
||
|
}
|
||
|
print("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;
|
||
|
}
|
||
|
public void run() {
|
||
|
try {
|
||
|
while(!Thread.interrupted()) {
|
||
|
// Blocks until next piece of toast is available:
|
||
|
Toast t = butteredQueue.take();
|
||
|
t.jam();
|
||
|
print(t);
|
||
|
finishedQueue.put(t);
|
||
|
}
|
||
|
} catch(InterruptedException e) {
|
||
|
print("Jammer interrupted");
|
||
|
}
|
||
|
print("Jammer off");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Consume the toast:
|
||
|
class Eater implements Runnable {
|
||
|
private ToastQueue finishedQueue;
|
||
|
private int counter = 0;
|
||
|
public Eater(ToastQueue finished) {
|
||
|
finishedQueue = finished;
|
||
|
}
|
||
|
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) {
|
||
|
print(">>>> Error: " + t);
|
||
|
System.exit(1);
|
||
|
} else
|
||
|
print("Chomp! " + t);
|
||
|
}
|
||
|
} catch(InterruptedException e) {
|
||
|
print("Eater interrupted");
|
||
|
}
|
||
|
print("Eater off");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class ToastOMatic {
|
||
|
public static void main(String[] args) throws Exception {
|
||
|
ToastQueue dryQueue = new ToastQueue(),
|
||
|
butteredQueue = new ToastQueue(),
|
||
|
finishedQueue = new ToastQueue();
|
||
|
ExecutorService exec = Executors.newCachedThreadPool();
|
||
|
exec.execute(new Toaster(dryQueue));
|
||
|
exec.execute(new Butterer(dryQueue, butteredQueue));
|
||
|
exec.execute(new Jammer(butteredQueue, finishedQueue));
|
||
|
exec.execute(new Eater(finishedQueue));
|
||
|
TimeUnit.SECONDS.sleep(5);
|
||
|
exec.shutdownNow();
|
||
|
}
|
||
|
} /* (Execute to see output) *///:~
|