OnJava8-Examples/threads/CarBuilder.java

313 lines
9.6 KiB
Java
Raw Normal View History

2016-07-05 14:46:09 -06:00
// threads/CarBuilder.java
2015-12-15 11:47:04 -08:00
// (c)2016 MindView LLC: see Copyright.txt
2015-11-15 15:51:35 -08:00
// We make no guarantees that this code is fit for any purpose.
// Visit http://mindviewinc.com/Books/OnJava/ for more book information.
2016-01-25 18:05:55 -08:00
// A complex example of tasks working together
2015-06-15 17:47:35 -07:00
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++);
2015-11-03 12:00:44 -08:00
System.out.println("ChassisBuilder created " + c);
2015-06-15 17:47:35 -07:00
// Insert into queue
carQueue.put(c);
}
} catch(InterruptedException e) {
2015-11-03 12:00:44 -08:00
System.out.println("Interrupted: ChassisBuilder");
2015-06-15 17:47:35 -07:00
}
2015-11-03 12:00:44 -08:00
System.out.println("ChassisBuilder off");
2015-06-15 17:47:35 -07:00
}
}
class Assembler implements Runnable {
private CarQueue chassisQueue, finishingQueue;
private Car car;
private CyclicBarrier barrier = new CyclicBarrier(4);
private RobotPool robotPool;
2016-01-25 18:05:55 -08:00
public
Assembler(CarQueue cq, CarQueue fq, RobotPool rp) {
2015-06-15 17:47:35 -07:00
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) {
2016-01-25 18:05:55 -08:00
System.out.println(
"Exiting Assembler via interrupt");
2015-06-15 17:47:35 -07:00
} catch(BrokenBarrierException e) {
// This one we want to know about
throw new RuntimeException(e);
}
2015-11-03 12:00:44 -08:00
System.out.println("Assembler off");
2015-06-15 17:47:35 -07:00
}
}
class Reporter implements Runnable {
private CarQueue carQueue;
public Reporter(CarQueue cq) { carQueue = cq; }
@Override
public void run() {
try {
while(!Thread.interrupted()) {
2015-11-03 12:00:44 -08:00
System.out.println(carQueue.take());
2015-06-15 17:47:35 -07:00
}
} catch(InterruptedException e) {
2016-01-25 18:05:55 -08:00
System.out.println(
"Exiting Reporter via interrupt");
2015-06-15 17:47:35 -07:00
}
2015-11-03 12:00:44 -08:00
System.out.println("Reporter off");
2015-06-15 17:47:35 -07:00
}
}
abstract class Robot implements Runnable {
private RobotPool pool;
public Robot(RobotPool p) { pool = p; }
protected Assembler assembler;
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:
abstract protected 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) {
2015-12-02 09:20:27 -08:00
System.out.println(
"Exiting " + this + " via interrupt");
2015-06-15 17:47:35 -07:00
} catch(BrokenBarrierException e) {
// This one we want to know about
throw new RuntimeException(e);
}
2015-11-03 12:00:44 -08:00
System.out.println(this + " off");
2015-06-15 17:47:35 -07:00
}
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();
}
2016-01-25 18:05:55 -08:00
public String toString() {
return getClass().getName();
}
2015-06-15 17:47:35 -07:00
}
class EngineRobot extends Robot {
public EngineRobot(RobotPool pool) { super(pool); }
protected void performService() {
2015-11-03 12:00:44 -08:00
System.out.println(this + " installing engine");
2015-06-15 17:47:35 -07:00
assembler.car().addEngine();
}
}
class DriveTrainRobot extends Robot {
public DriveTrainRobot(RobotPool pool) { super(pool); }
protected void performService() {
2015-11-03 12:00:44 -08:00
System.out.println(this + " installing DriveTrain");
2015-06-15 17:47:35 -07:00
assembler.car().addDriveTrain();
}
}
class WheelRobot extends Robot {
public WheelRobot(RobotPool pool) { super(pool); }
protected void performService() {
2015-11-03 12:00:44 -08:00
System.out.println(this + " installing Wheels");
2015-06-15 17:47:35 -07:00
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 {
2016-01-25 18:05:55 -08:00
public static void
main(String[] args) throws Exception {
2015-06-15 17:47:35 -07:00
CarQueue chassisQueue = new CarQueue(),
finishingQueue = new CarQueue();
2016-01-25 18:05:55 -08:00
ExecutorService es = Executors.newCachedThreadPool();
2015-06-15 17:47:35 -07:00
RobotPool robotPool = new RobotPool();
2016-01-25 18:05:55 -08:00
es.execute(new EngineRobot(robotPool));
es.execute(new DriveTrainRobot(robotPool));
es.execute(new WheelRobot(robotPool));
es.execute(new Assembler(
2015-06-15 17:47:35 -07:00
chassisQueue, finishingQueue, robotPool));
2016-01-25 18:05:55 -08:00
es.execute(new Reporter(finishingQueue));
2015-06-15 17:47:35 -07:00
// Start everything running by producing chassis:
2016-01-25 18:05:55 -08:00
es.execute(new ChassisBuilder(chassisQueue));
2015-06-15 17:47:35 -07:00
TimeUnit.SECONDS.sleep(7);
2016-01-25 18:05:55 -08:00
es.shutdownNow();
2015-06-15 17:47:35 -07:00
}
2015-09-07 11:44:36 -06:00
}
/* Output:
2015-06-15 17:47:35 -07:00
ChassisBuilder created Car 0 [ engine: false driveTrain:
false wheels: false ]
2016-07-22 14:45:35 -06:00
WheelRobot installing Wheels
2015-06-15 17:47:35 -07:00
DriveTrainRobot installing DriveTrain
2016-07-27 11:12:11 -06:00
EngineRobot installing engine
2015-06-15 17:47:35 -07:00
Car 0 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 1 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
2016-07-22 14:45:35 -06:00
DriveTrainRobot installing DriveTrain
2015-06-15 17:47:35 -07:00
Car 1 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 2 [ engine: false driveTrain:
false wheels: false ]
DriveTrainRobot installing DriveTrain
WheelRobot installing Wheels
2016-07-27 11:12:11 -06:00
EngineRobot installing engine
2015-06-15 17:47:35 -07:00
Car 2 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 3 [ engine: false driveTrain:
false wheels: false ]
2016-07-22 14:45:35 -06:00
DriveTrainRobot installing DriveTrain
2016-07-27 11:12:11 -06:00
WheelRobot installing Wheels
EngineRobot installing engine
2015-06-15 17:47:35 -07:00
Car 3 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 4 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
DriveTrainRobot installing DriveTrain
2016-07-22 14:45:35 -06:00
WheelRobot installing Wheels
2015-06-15 17:47:35 -07:00
Car 4 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 5 [ engine: false driveTrain:
false wheels: false ]
2016-07-22 14:45:35 -06:00
EngineRobot installing engine
2015-06-15 17:47:35 -07:00
WheelRobot installing Wheels
2016-07-27 11:12:11 -06:00
DriveTrainRobot installing DriveTrain
2015-06-15 17:47:35 -07:00
Car 5 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 6 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
2016-07-22 14:45:35 -06:00
DriveTrainRobot installing DriveTrain
2015-06-15 17:47:35 -07:00
Car 6 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 7 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
2016-07-22 14:45:35 -06:00
DriveTrainRobot installing DriveTrain
2015-06-15 17:47:35 -07:00
Car 7 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 8 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
WheelRobot installing Wheels
2016-07-27 11:12:11 -06:00
DriveTrainRobot installing DriveTrain
2015-06-15 17:47:35 -07:00
Car 8 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 9 [ engine: false driveTrain:
false wheels: false ]
DriveTrainRobot installing DriveTrain
EngineRobot installing engine
2016-07-27 11:12:11 -06:00
WheelRobot installing Wheels
2015-06-15 17:47:35 -07:00
Car 9 [ engine: true driveTrain: true wheels: true ]
ChassisBuilder created Car 10 [ engine: false driveTrain:
false wheels: false ]
2016-07-22 14:45:35 -06:00
DriveTrainRobot installing DriveTrain
2015-06-15 17:47:35 -07:00
EngineRobot installing engine
2016-07-27 11:12:11 -06:00
WheelRobot installing Wheels
2015-06-15 17:47:35 -07:00
Car 10 [ engine: true driveTrain: true wheels: true ]
2016-07-22 14:45:35 -06:00
ChassisBuilder created Car 11 [ engine: false driveTrain:
false wheels: false ]
EngineRobot installing engine
2016-07-27 11:12:11 -06:00
WheelRobot installing Wheels
DriveTrainRobot installing DriveTrain
2016-07-22 14:45:35 -06:00
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 ]
2016-07-27 11:12:11 -06:00
Exiting Assembler via interrupt
2015-06-15 17:47:35 -07:00
Exiting EngineRobot via interrupt
2016-07-22 14:45:35 -06:00
Exiting WheelRobot via interrupt
2016-07-27 11:12:11 -06:00
Exiting DriveTrainRobot via interrupt
DriveTrainRobot off
Exiting Reporter via interrupt
2016-07-22 14:45:35 -06:00
Interrupted: ChassisBuilder
2016-07-27 11:12:11 -06:00
Reporter off
2016-07-22 14:45:35 -06:00
WheelRobot off
2016-07-27 11:12:11 -06:00
EngineRobot off
2016-07-22 14:45:35 -06:00
Assembler off
2016-07-27 11:12:11 -06:00
ChassisBuilder off
2015-09-07 11:44:36 -06:00
*/