Removed simulations

This commit is contained in:
Bruce Eckel 2016-12-30 22:38:14 -08:00
parent 06d63a1c04
commit 49ea4c8d4b
7 changed files with 0 additions and 1392 deletions

View File

@ -1,218 +0,0 @@
// lowlevel/BankTellerSimulation.java
// (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.
// Using queues and multithreading
// {java BankTellerSimulation 5}
import java.util.concurrent.*;
import java.util.*;
// Read-only objects don't require synchronization:
class Customer {
private final int serviceTime;
public Customer(int tm) { serviceTime = tm; }
public int getServiceTime() { return serviceTime; }
public String toString() {
return "[" + serviceTime + "]";
}
}
// Teach the customer line to display itself:
class CustomerLine extends ArrayBlockingQueue<Customer> {
public CustomerLine(int maxLineSize) {
super(maxLineSize);
}
@Override
public String toString() {
if(this.size() == 0)
return "[Empty]";
StringBuilder result = new StringBuilder();
for(Customer customer : this)
result.append(customer);
return result.toString();
}
}
// Randomly add customers to a queue:
class CustomerSupplier implements Runnable {
private CustomerLine customers;
private static SplittableRandom rand = new SplittableRandom(47);
public CustomerSupplier(CustomerLine cq) {
customers = cq;
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(rand.nextInt(300));
customers.put(new Customer(rand.nextInt(1000)));
}
} catch(InterruptedException e) {
System.out.println("CustomerSupplier interrupted");
}
System.out.println("CustomerSupplier terminating");
}
}
class Teller implements Runnable, Comparable<Teller> {
private static int counter = 0;
private final int id = counter++;
// Customers served during this shift:
private int customersServed = 0;
private CustomerLine customers;
private boolean servingCustomerLine = true;
public Teller(CustomerLine cq) { customers = cq; }
public void run() {
try {
while(!Thread.interrupted()) {
Customer customer = customers.take();
TimeUnit.MILLISECONDS.sleep(
customer.getServiceTime());
synchronized(this) {
customersServed++;
while(!servingCustomerLine)
wait();
}
}
} catch(InterruptedException e) {
System.out.println(this + "interrupted");
}
System.out.println(this + "terminating");
}
public synchronized void doSomethingElse() {
customersServed = 0;
servingCustomerLine = false;
}
public synchronized void serveCustomerLine() {
assert !servingCustomerLine:
"already serving: " + this;
servingCustomerLine = true;
notifyAll();
}
public String toString() {
return "Teller " + id + " ";
}
public String shortString() { return "T" + id; }
// Used by priority queue:
public synchronized int compareTo(Teller other) {
return customersServed < other.customersServed ? -1 :
(customersServed == other.customersServed ? 0 : 1);
}
}
class TellerManager implements Runnable {
private ExecutorService exec;
private CustomerLine customers;
private PriorityQueue<Teller> workingTellers =
new PriorityQueue<>();
private Queue<Teller> tellersDoingOtherThings =
new LinkedList<>();
private int adjustmentPeriod;
public TellerManager(ExecutorService e,
CustomerLine customers, int adjustmentPeriod) {
exec = e;
this.customers = customers;
this.adjustmentPeriod = adjustmentPeriod;
// Start with a single teller:
Teller teller = new Teller(customers);
exec.execute(teller);
workingTellers.add(teller);
}
public void adjustTellerNumber() {
// This is actually a control system. By adjusting
// the numbers, you can reveal stability issues in
// the control mechanism.
// If line is too long, add another teller:
if(customers.size() / workingTellers.size() > 2) {
// If tellers are on break or doing
// another job, bring one back:
if(tellersDoingOtherThings.size() > 0) {
Teller teller =
tellersDoingOtherThings.remove();
teller.serveCustomerLine();
workingTellers.offer(teller);
return;
}
// Else create (hire) a new teller
Teller teller = new Teller(customers);
exec.execute(teller);
workingTellers.add(teller);
return;
}
// If line is short enough, remove a teller:
if(workingTellers.size() > 1 &&
customers.size() / workingTellers.size() < 2)
reassignOneTeller();
// If there is no line, we only need one teller:
if(customers.size() == 0)
while(workingTellers.size() > 1)
reassignOneTeller();
}
// Give a teller a different job or a break:
private void reassignOneTeller() {
Teller teller = workingTellers.poll();
teller.doSomethingElse();
tellersDoingOtherThings.offer(teller);
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(adjustmentPeriod);
adjustTellerNumber();
System.out.print(customers + " { ");
for(Teller teller : workingTellers)
System.out.print(teller.shortString() + " ");
System.out.println("}");
}
} catch(InterruptedException e) {
System.out.println(this + "interrupted");
}
System.out.println(this + "terminating");
}
@Override
public String toString() { return "TellerManager "; }
}
public class BankTellerSimulation {
static final int MAX_LINE_SIZE = 50;
static final int ADJUSTMENT_PERIOD = 1000;
public static void
main(String[] args) throws Exception {
ExecutorService es = Executors.newCachedThreadPool();
// If line is too long, customers will leave:
CustomerLine customers =
new CustomerLine(MAX_LINE_SIZE);
es.execute(new CustomerSupplier(customers));
// Manager will add and remove tellers as necessary:
es.execute(new TellerManager(
es, customers, ADJUSTMENT_PERIOD));
if(args.length > 0) // Optional argument
TimeUnit.SECONDS.sleep(new Integer(args[0]));
else {
System.out.println("Press 'Enter' to quit");
System.in.read();
}
es.shutdownNow();
}
}
/* Output:
[768][193][807][125] { T1 T0 }
[125][634][682][267][954][506][639][213] { T2 T0 T1 }
[213][592][770][919][552][727][998][902] { T2 T0 T1 }
[552][727][998][902][769][373][313][683][177][526] { T3 T2
T1 T0 }
TellerManager interrupted
Teller 3 interrupted
CustomerSupplier interrupted
Teller 3 terminating
Teller 2 interrupted
Teller 2 terminating
TellerManager terminating
Teller 1 interrupted
Teller 0 interrupted
Teller 0 terminating
Teller 1 terminating
CustomerSupplier terminating
*/

View File

@ -1,312 +0,0 @@
// lowlevel/CarBuilder.java
// (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.
// A complex example of tasks working together
import java.util.concurrent.*;
import java.util.*;
class Car {
private final int id;
private boolean
engine = false, driveTrain = false, wheels = false;
public Car(int idn) { id = idn; }
// Empty Car object:
public Car() { id = -1; }
public synchronized int getId() { return id; }
public synchronized void addEngine() { engine = true; }
public synchronized void addDriveTrain() {
driveTrain = true;
}
public synchronized void addWheels() { wheels = true; }
public synchronized String toString() {
return "Car " + id + " [" + " engine: " + engine
+ " driveTrain: " + driveTrain
+ " wheels: " + wheels + " ]";
}
}
class CarQueue extends LinkedBlockingQueue<Car> {}
class ChassisBuilder implements Runnable {
private CarQueue carQueue;
private int counter = 0;
public ChassisBuilder(CarQueue cq) { carQueue = cq; }
@Override
public void run() {
try {
while(!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(500);
// Make chassis:
Car c = new Car(counter++);
System.out.println("ChassisBuilder created " + c);
// Insert into queue
carQueue.put(c);
}
} catch(InterruptedException e) {
System.out.println("Interrupted: ChassisBuilder");
}
System.out.println("ChassisBuilder off");
}
}
class Assembler implements Runnable {
private CarQueue chassisQueue, finishingQueue;
private Car car;
private CyclicBarrier barrier = new CyclicBarrier(4);
private RobotPool robotPool;
public
Assembler(CarQueue cq, CarQueue fq, RobotPool rp) {
chassisQueue = cq;
finishingQueue = fq;
robotPool = rp;
}
public Car car() { return car; }
public CyclicBarrier barrier() { return barrier; }
@Override
public void run() {
try {
while(!Thread.interrupted()) {
// Blocks until chassis is available:
car = chassisQueue.take();
// Hire robots to perform work:
robotPool.hire(EngineRobot.class, this);
robotPool.hire(DriveTrainRobot.class, this);
robotPool.hire(WheelRobot.class, this);
barrier.await(); // Until the robots finish
// Put car into finishingQueue for further work
finishingQueue.put(car);
}
} catch(InterruptedException e) {
System.out.println(
"Exiting Assembler via interrupt");
} catch(BrokenBarrierException e) {
// This one we want to know about
throw new RuntimeException(e);
}
System.out.println("Assembler off");
}
}
class Reporter implements Runnable {
private CarQueue carQueue;
public Reporter(CarQueue cq) { carQueue = cq; }
@Override
public void run() {
try {
while(!Thread.interrupted()) {
System.out.println(carQueue.take());
}
} catch(InterruptedException e) {
System.out.println(
"Exiting Reporter via interrupt");
}
System.out.println("Reporter off");
}
}
abstract class Robot implements Runnable {
private RobotPool pool;
protected Assembler assembler;
public Robot(RobotPool p) { pool = p; }
public Robot assignAssembler(Assembler assembler) {
this.assembler = assembler;
return this;
}
private boolean engage = false;
public synchronized void engage() {
engage = true;
notifyAll();
}
// The part of run() that's different for each robot:
protected abstract void performService();
public void run() {
try {
powerDown(); // Wait until needed
while(!Thread.interrupted()) {
performService();
assembler.barrier().await(); // Synchronize
// We're done with that job...
powerDown();
}
} catch(InterruptedException e) {
System.out.println(
"Exiting " + this + " via interrupt");
} catch(BrokenBarrierException e) {
// This one we want to know about
throw new RuntimeException(e);
}
System.out.println(this + " off");
}
private synchronized void
powerDown() throws InterruptedException {
engage = false;
assembler = null; // Disconnect from the Assembler
// Put ourselves back in the available pool:
pool.release(this);
while(engage == false) // Power down
wait();
}
public String toString() {
return getClass().getName();
}
}
class EngineRobot extends Robot {
public EngineRobot(RobotPool pool) { super(pool); }
protected void performService() {
System.out.println(this + " installing engine");
assembler.car().addEngine();
}
}
class DriveTrainRobot extends Robot {
public DriveTrainRobot(RobotPool pool) { super(pool); }
protected void performService() {
System.out.println(this + " installing DriveTrain");
assembler.car().addDriveTrain();
}
}
class WheelRobot extends Robot {
public WheelRobot(RobotPool pool) { super(pool); }
protected void performService() {
System.out.println(this + " installing Wheels");
assembler.car().addWheels();
}
}
class RobotPool {
// Quietly prevents identical entries:
private Set<Robot> pool = new HashSet<>();
public synchronized void add(Robot r) {
pool.add(r);
notifyAll();
}
public synchronized void
hire(Class<? extends Robot> robotType, Assembler d)
throws InterruptedException {
for(Robot r : pool)
if(r.getClass().equals(robotType)) {
pool.remove(r);
r.assignAssembler(d);
r.engage(); // Power it up to do the task
return;
}
wait(); // None available
hire(robotType, d); // Try again, recursively
}
public synchronized void release(Robot r) { add(r); }
}
public class CarBuilder {
public static void
main(String[] args) throws Exception {
CarQueue chassisQueue = new CarQueue(),
finishingQueue = new CarQueue();
ExecutorService es = Executors.newCachedThreadPool();
RobotPool robotPool = new RobotPool();
es.execute(new EngineRobot(robotPool));
es.execute(new DriveTrainRobot(robotPool));
es.execute(new WheelRobot(robotPool));
es.execute(new Assembler(
chassisQueue, finishingQueue, robotPool));
es.execute(new Reporter(finishingQueue));
// Start everything running by producing chassis:
es.execute(new ChassisBuilder(chassisQueue));
TimeUnit.SECONDS.sleep(7);
es.shutdownNow();
}
}
/* Output:
ChassisBuilder created Car 0 [ engine: false driveTrain:
false wheels: false ]
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
EngineRobot installing engine
Car 0 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 1 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 1 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 2 [ engine: false driveTrain:
false wheels: false ]
DriveTrainRobot installing DriveTrain
WheelRobot installing Wheels
EngineRobot installing engine
Car 2 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 3 [ engine: false driveTrain:
false wheels: false ]
DriveTrainRobot installing DriveTrain
WheelRobot installing Wheels
EngineRobot installing engine
Car 3 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 4 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
DriveTrainRobot installing DriveTrain
WheelRobot installing Wheels
Car 4 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 5 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 5 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 6 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 6 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 7 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 7 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 8 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 8 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 9 [ engine: false driveTrain:
false wheels: false ]
DriveTrainRobot installing DriveTrain
EngineRobot installing engine
WheelRobot installing Wheels
Car 9 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 10 [ engine: false driveTrain:
false wheels: false ]
DriveTrainRobot installing DriveTrain
EngineRobot installing engine
WheelRobot installing Wheels
Car 10 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 11 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
Car 11 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 12 [ engine: false driveTrain:
false wheels: false ]
DriveTrainRobot installing DriveTrain
WheelRobot installing Wheels
EngineRobot installing engine
Car 12 [ engine: true driveTrain: true wheels: true ]
Exiting Assembler via interrupt
Exiting EngineRobot via interrupt
Exiting WheelRobot via interrupt
Exiting DriveTrainRobot via interrupt
DriveTrainRobot off
Exiting Reporter via interrupt
Interrupted: ChassisBuilder
Reporter off
WheelRobot off
EngineRobot off
Assembler off
ChassisBuilder off
*/

View File

@ -1,202 +0,0 @@
// lowlevel/GreenhouseScheduler.java
// (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.
// Rewriting innerclasses/GreenhouseController.java
// to use a ScheduledThreadPoolExecutor
// {java GreenhouseScheduler 5000}
import java.util.concurrent.*;
import java.util.*;
public class GreenhouseScheduler {
private volatile boolean light = false;
private volatile boolean water = false;
private String thermostat = "Day";
public synchronized String getThermostat() {
return thermostat;
}
public synchronized void setThermostat(String value) {
thermostat = value;
}
ScheduledThreadPoolExecutor scheduler =
new ScheduledThreadPoolExecutor(10);
public void schedule(Runnable event, long delay) {
scheduler.schedule(event,delay,TimeUnit.MILLISECONDS);
}
public void
repeat(Runnable event, long initialDelay, long period) {
scheduler.scheduleAtFixedRate(
event, initialDelay, period, TimeUnit.MILLISECONDS);
}
class LightOn implements Runnable {
@Override
public void run() {
// Put hardware control code here to
// physically turn on the light.
System.out.println("Turning on lights");
light = true;
}
}
class LightOff implements Runnable {
@Override
public void run() {
// Put hardware control code here to
// physically turn off the light.
System.out.println("Turning off lights");
light = false;
}
}
class WaterOn implements Runnable {
@Override
public void run() {
// Put hardware control code here.
System.out.println("Turning greenhouse water on");
water = true;
}
}
class WaterOff implements Runnable {
@Override
public void run() {
// Put hardware control code here.
System.out.println("Turning greenhouse water off");
water = false;
}
}
class ThermostatNight implements Runnable {
@Override
public void run() {
// Put hardware control code here.
System.out.println("Thermostat to night setting");
setThermostat("Night");
}
}
class ThermostatDay implements Runnable {
@Override
public void run() {
// Put hardware control code here.
System.out.println("Thermostat to day setting");
setThermostat("Day");
}
}
class Bell implements Runnable {
@Override
public void run() { System.out.println("Bing!"); }
}
class Terminate implements Runnable {
@Override
public void run() {
System.out.println("Terminating");
scheduler.shutdownNow();
// Must start a separate task to do this job,
// since the scheduler was shut down:
new Thread() {
@Override
public void run() {
for(DataPoint d : data)
System.out.println(d);
}
}.start();
}
}
// New feature: data collection
static class DataPoint {
final Calendar time;
final double temperature;
final double humidity;
public DataPoint(Calendar d, double temp, double hum) {
time = d;
temperature = temp;
humidity = hum;
}
@Override
public String toString() {
return time.getTime() +
String.format(
" temperature: %1$.1f humidity: %2$.2f",
temperature, humidity);
}
}
private Calendar lastTime = Calendar.getInstance();
{ // Adjust date to the half hour
lastTime.set(Calendar.MINUTE, 30);
lastTime.set(Calendar.SECOND, 00);
}
private double lastTemp = 65.0f;
private int tempDirection = +1;
private double lastHumidity = 50.0f;
private int humidityDirection = +1;
private SplittableRandom rand = new SplittableRandom(47);
List<DataPoint> data = Collections.synchronizedList(
new ArrayList<>());
class CollectData implements Runnable {
@Override
public void run() {
System.out.println("Collecting data");
synchronized(GreenhouseScheduler.this) {
// Pretend the interval is longer than it is:
lastTime.set(Calendar.MINUTE,
lastTime.get(Calendar.MINUTE) + 30);
// One in 5 chances of reversing the direction:
if(rand.nextInt(5) == 4)
tempDirection = -tempDirection;
// Store previous value:
lastTemp +=
tempDirection * (1.0f + rand.nextDouble());
if(rand.nextInt(5) == 4)
humidityDirection = -humidityDirection;
lastHumidity +=
humidityDirection * rand.nextDouble();
// Calendar must be cloned, otherwise all
// DataPoints hold references to same lastTime.
// For basic object like Calendar, clone() is OK.
data.add(new DataPoint((Calendar)lastTime.clone(),
lastTemp, lastHumidity));
}
}
}
public static void main(String[] args) {
GreenhouseScheduler gh = new GreenhouseScheduler();
gh.schedule(gh.new Terminate(), 5000);
// Former "Restart" class not necessary:
gh.repeat(gh.new Bell(), 0, 1000);
gh.repeat(gh.new ThermostatNight(), 0, 2000);
gh.repeat(gh.new LightOn(), 0, 200);
gh.repeat(gh.new LightOff(), 0, 400);
gh.repeat(gh.new WaterOn(), 0, 600);
gh.repeat(gh.new WaterOff(), 0, 800);
gh.repeat(gh.new ThermostatDay(), 0, 1400);
gh.repeat(gh.new CollectData(), 500, 500);
}
}
/* Output: (First and Last 10 Lines)
Bing!
Thermostat to night setting
Turning on lights
Turning off lights
Turning greenhouse water on
Turning greenhouse water off
Thermostat to day setting
Turning on lights
Turning on lights
Turning off lights
...________...________...________...________...
Terminating
Wed Jul 27 11:00:00 MDT 2016 temperature: 66.3 humidity:
50.20
Wed Jul 27 11:30:00 MDT 2016 temperature: 67.3 humidity:
51.02
Wed Jul 27 12:00:00 MDT 2016 temperature: 68.8 humidity:
51.82
Wed Jul 27 12:30:00 MDT 2016 temperature: 70.0 humidity:
52.19
Wed Jul 27 13:00:00 MDT 2016 temperature: 71.5 humidity:
52.99
Wed Jul 27 13:30:00 MDT 2016 temperature: 73.0 humidity:
53.32
Wed Jul 27 14:00:00 MDT 2016 temperature: 74.4 humidity:
53.99
Wed Jul 27 14:30:00 MDT 2016 temperature: 75.5 humidity:
54.40
Wed Jul 27 15:00:00 MDT 2016 temperature: 76.8 humidity:
53.96
*/

View File

@ -1,132 +0,0 @@
// lowlevel/HorseRace.java
// (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.
// Using CyclicBarriers
import java.util.concurrent.*;
import java.util.*;
import onjava.Nap;
class Horse implements Runnable {
private static int counter = 0;
private final int id = counter++;
private int strides = 0;
private static SplittableRandom rand = new SplittableRandom(47);
private static CyclicBarrier barrier;
public Horse(CyclicBarrier b) { barrier = b; }
public synchronized int getStrides() { return strides; }
@Override
public void run() {
try {
while(!Thread.interrupted()) {
synchronized(this) {
strides += rand.nextInt(3); // Yeilds 0, 1 or 2
}
barrier.await();
}
} catch(InterruptedException e) {
// A legitimate way to exit
} catch(BrokenBarrierException e) {
// This one we want to know about
throw new RuntimeException(e);
}
}
@Override
public String toString() { return "Horse " + id + " "; }
public String tracks() {
StringBuilder s = new StringBuilder();
for(int i = 0; i < getStrides(); i++)
s.append("*");
s.append(id);
return s.toString();
}
}
public class HorseRace {
static final int FINISH_LINE = 60;
private List<Horse> horses = new ArrayList<>();
private ExecutorService exec =
Executors.newCachedThreadPool();
private CyclicBarrier barrier;
public HorseRace(int nHorses, final int pause) {
barrier = new CyclicBarrier(nHorses, () -> {
StringBuilder s = new StringBuilder();
for(int i = 0; i < FINISH_LINE; i++)
s.append("="); // The fence on the racetrack
System.out.println(s);
for(Horse horse : horses)
System.out.println(horse.tracks());
for(Horse horse : horses)
if(horse.getStrides() >= FINISH_LINE) {
System.out.println(horse + "won!");
exec.shutdownNow();
return;
}
new Nap(pause);
});
for(int i = 0; i < nHorses; i++) {
Horse horse = new Horse(barrier);
horses.add(horse);
exec.execute(horse);
}
}
public static void main(String[] args) {
int nHorses = 7;
int pause = 200;
if(args.length > 0) { // Optional argument
int n = new Integer(args[0]);
nHorses = n > 0 ? n : nHorses;
}
if(args.length > 1) { // Optional argument
int p = new Integer(args[1]);
pause = p > -1 ? p : pause;
}
new HorseRace(nHorses, pause);
}
}
/* Output: (First and Last 18 Lines)
===========================================================
=
0
**1
2
*3
**4
*5
**6
===========================================================
=
**0
***1
*2
*3
****4
**5
****6
===========================================================
=
**0
...________...________...________...________...
**********************************************6
===========================================================
=
**************************************************0
*************************************************1
*********************************************2
***********************************************************
3
*****************************************************4
*****************************************************5
***********************************************6
===========================================================
=
****************************************************0
*************************************************1
***********************************************2
***********************************************************
*3
*******************************************************4
*******************************************************5
***********************************************6
Horse 3 won!
*/

View File

@ -1,94 +0,0 @@
// lowlevel/Restaurant.java
// (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.
// The producer-consumer approach to task cooperation
import java.util.concurrent.*;
class Meal {
private final int orderNum;
public Meal(int orderNum) { this.orderNum = orderNum; }
@Override
public String toString() { return "Meal " + orderNum; }
}
class WaitPerson implements Runnable {
private Restaurant restaurant;
public WaitPerson(Restaurant r) { restaurant = r; }
@Override
public void run() {
try {
while(!Thread.interrupted()) {
synchronized(this) {
while(restaurant.meal == null)
wait(); // ... for the chef to produce a meal
}
System.out.println(
"Waitperson got " + restaurant.meal);
synchronized(restaurant.chef) {
restaurant.meal = null;
restaurant.chef.notifyAll(); // Ready for more
}
}
} catch(InterruptedException e) {
System.out.println("WaitPerson interrupted");
}
}
}
class Chef implements Runnable {
private Restaurant restaurant;
private int count = 0;
public Chef(Restaurant r) { restaurant = r; }
@Override
public void run() {
try {
while(!Thread.interrupted()) {
synchronized(this) {
while(restaurant.meal != null)
wait(); // ... for the meal to be taken
}
if(++count == 10) {
System.out.println("Out of food, closing");
restaurant.exec.shutdownNow();
}
System.out.print("Order up! ");
synchronized(restaurant.waitPerson) {
restaurant.meal = new Meal(count);
restaurant.waitPerson.notifyAll();
}
TimeUnit.MILLISECONDS.sleep(100);
}
} catch(InterruptedException e) {
System.out.println("Chef interrupted");
}
}
}
public class Restaurant {
Meal meal;
ExecutorService exec = Executors.newCachedThreadPool();
WaitPerson waitPerson = new WaitPerson(this);
Chef chef = new Chef(this);
public Restaurant() {
exec.execute(chef);
exec.execute(waitPerson);
}
public static void main(String[] args) {
new Restaurant();
}
}
/* Output:
Order up! Waitperson got Meal 1
Order up! Waitperson got Meal 2
Order up! Waitperson got Meal 3
Order up! Waitperson got Meal 4
Order up! Waitperson got Meal 5
Order up! Waitperson got Meal 6
Order up! Waitperson got Meal 7
Order up! Waitperson got Meal 8
Order up! Waitperson got Meal 9
Out of food, closing
Order up! WaitPerson interrupted
Chef interrupted
*/

View File

@ -1,204 +0,0 @@
// lowlevel/ToastOMatic.java
// (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.
// 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
*/

View File

@ -1,230 +0,0 @@
// lowlevel/restaurant2/RestaurantWithQueues.java
// (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.
// {java threads.restaurant2.RestaurantWithQueues 5}
package threads.restaurant2;
import enums.menu.*;
import java.util.concurrent.*;
import java.util.*;
// This is given to the waiter, who gives it to the chef:
class Order { // (A data-transfer object)
private static int counter = 0;
private final int id = counter++;
private final Customer customer;
private final WaitPerson waitPerson;
private final Food food;
public Order(Customer cust, WaitPerson wp, Food f) {
customer = cust;
waitPerson = wp;
food = f;
}
public Food item() { return food; }
public Customer getCustomer() { return customer; }
public WaitPerson getWaitPerson() { return waitPerson; }
@Override
public String toString() {
return "Order: " + id + " item: " + food +
" for: " + customer +
" served by: " + waitPerson;
}
}
// This comes back from the chef:
class Plate {
private final Order order;
private final Food food;
public Plate(Order ord, Food f) {
order = ord;
food = f;
}
public Order getOrder() { return order; }
public Food getFood() { return food; }
@Override
public String toString() { return food.toString(); }
}
class Customer implements Runnable {
private static int counter = 0;
private final int id = counter++;
private final WaitPerson waitPerson;
// Only one course at a time can be received:
private SynchronousQueue<Plate> placeSetting =
new SynchronousQueue<>();
public Customer(WaitPerson w) { waitPerson = w; }
public void
deliver(Plate p) throws InterruptedException {
// Only blocks if customer is still
// eating the previous course:
placeSetting.put(p);
}
@Override
public void run() {
for(Course course : Course.values()) {
Food food = course.randomSelection();
try {
waitPerson.placeOrder(this, food);
// Blocks until course is delivered:
System.out.println(
this + "eating " + placeSetting.take());
} catch(InterruptedException e) {
System.out.println(this + "waiting for " +
course + " interrupted");
break;
}
}
System.out.println(this + "finished meal, leaving");
}
@Override
public String toString() {
return "Customer " + id + " ";
}
}
class WaitPerson implements Runnable {
private static int counter = 0;
private final int id = counter++;
private final Restaurant restaurant;
BlockingQueue<Plate> filledOrders =
new LinkedBlockingQueue<>();
public WaitPerson(Restaurant rest) {
restaurant = rest;
}
public void placeOrder(Customer cust, Food food) {
try {
// Shouldn't actually block because this is
// a LinkedBlockingQueue with no size limit:
restaurant.orders.put(new Order(cust, this, food));
} catch(InterruptedException e) {
System.out.println(
this + " placeOrder interrupted");
}
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
// Blocks until a course is ready
Plate plate = filledOrders.take();
System.out.println(this + "received " + plate +
" delivering to " +
plate.getOrder().getCustomer());
plate.getOrder().getCustomer().deliver(plate);
}
} catch(InterruptedException e) {
System.out.println(this + " interrupted");
}
System.out.println(this + " off duty");
}
@Override
public String toString() {
return "WaitPerson " + id + " ";
}
}
class Chef implements Runnable {
private static int counter = 0;
private final int id = counter++;
private final Restaurant restaurant;
private static SplittableRandom rand = new SplittableRandom(47);
public Chef(Restaurant rest) { restaurant = rest; }
@Override
public void run() {
try {
while(!Thread.interrupted()) {
// Blocks until an order appears:
Order order = restaurant.orders.take();
Food requestedItem = order.item();
// Time to prepare order:
TimeUnit.MILLISECONDS.sleep(rand.nextInt(500));
Plate plate = new Plate(order, requestedItem);
order.getWaitPerson().filledOrders.put(plate);
}
} catch(InterruptedException e) {
System.out.println(this + " interrupted");
}
System.out.println(this + " off duty");
}
@Override
public String toString() { return "Chef " + id + " "; }
}
class Restaurant implements Runnable {
private List<WaitPerson> waitPersons =
new ArrayList<>();
private List<Chef> chefs = new ArrayList<>();
private ExecutorService exec;
private static SplittableRandom rand = new SplittableRandom(47);
BlockingQueue<Order>
orders = new LinkedBlockingQueue<>();
public Restaurant(ExecutorService e, int nWaitPersons,
int nChefs) {
exec = e;
for(int i = 0; i < nWaitPersons; i++) {
WaitPerson waitPerson = new WaitPerson(this);
waitPersons.add(waitPerson);
exec.execute(waitPerson);
}
for(int i = 0; i < nChefs; i++) {
Chef chef = new Chef(this);
chefs.add(chef);
exec.execute(chef);
}
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
// A new customer arrives; assign a WaitPerson:
WaitPerson wp = waitPersons.get(
rand.nextInt(waitPersons.size()));
Customer c = new Customer(wp);
exec.execute(c);
TimeUnit.MILLISECONDS.sleep(100);
}
} catch(InterruptedException e) {
System.out.println("Restaurant interrupted");
}
System.out.println("Restaurant closing");
}
}
public class RestaurantWithQueues {
public static void
main(String[] args) throws Exception {
ExecutorService es = Executors.newCachedThreadPool();
Restaurant restaurant = new Restaurant(es, 5, 2);
es.execute(restaurant);
if(args.length > 0) // Optional argument
TimeUnit.SECONDS.sleep(new Integer(args[0]));
else {
System.out.println("Press 'Enter' to quit");
System.in.read();
}
es.shutdownNow();
}
}
/* Output: (First and Last 10 Lines)
WaitPerson 0 received SALAD delivering to Customer 0
Customer 0 eating SALAD
WaitPerson 2 received SPRING_ROLLS delivering to Customer 1
Customer 1 eating SPRING_ROLLS
WaitPerson 1 received SOUP delivering to Customer 2
Customer 2 eating SOUP
WaitPerson 0 received LENTILS delivering to Customer 0
Customer 0 eating LENTILS
WaitPerson 0 received SPRING_ROLLS delivering to Customer 3
Customer 3 eating SPRING_ROLLS
...________...________...________...________...
WaitPerson 2 off duty
Customer 33 finished meal, leaving
Customer 18 finished meal, leaving
Customer 35 finished meal, leaving
Customer 46 finished meal, leaving
WaitPerson 4 off duty
Customer 24 finished meal, leaving
Customer 30 finished meal, leaving
Customer 34 finished meal, leaving
Customer 48 finished meal, leaving
*/