多线程一个非常有意思的作用就是用于仿真,这篇博客就会结合几个仿真实例来综合运用一下前面所学的多线程并发知识。
一.银行出纳员仿真
问题描写叙述:银行会有非常多来办业务的顾客,他们会排队等待服务;对于银行方面他们派出出纳员来服务顾客,假设排队的顾客数量过多,银行就会添加
出纳员的数量,假设顾客的数目过少。则降低出纳员的数目;总之要保持一个平衡。
仿真思路:封装Customer类来表示顾客,每一个顾客对象都会有一个须要服务的时间;使用有限容量的堵塞队列CustomerLine来模拟顾客的排队队列;封装
CustomerGenerator类来产生顾客,然后将产生的顾客加入到CustomerLine中去。封装Teller类来表示银行的出纳员,Teller会从CustomerLine中取出。
Customer来进行服务。封装TellerManage来管理全部的Teller及依据顾客/出纳员的比例来调整服务顾客的Teller数量。在这里我们通过堵塞队列CustomerLine实现了Teller线程和CustomerGenerator线程之间的通信。
详细的实现代码例如以下:
package lkl;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 多线程模拟银行出纳员问题
* */
//模拟顾客类,全然仅仅是一个可读类。不须要同步
class Customer{
//该顾客所需服务时间
private final int serviceTime;
public Customer(final int serviceTime){
this.serviceTime = serviceTime;
}
public int getServiceTime(){
return serviceTime;
}
public String toString(){
return "["+serviceTime+"]";
}
}
//模拟顾客排队的队列,继承了堵塞队列
//是一个多线程共享对象,这个队列继承的是ArrayBlocingQueue
//是一个有最大长度的队列
class CustomerLine extends ArrayBlockingQueue<Customer>{
//指定同意队列的最大长度
public CustomerLine(int maxSize){
super(maxSize);
}
//重写toString()方法。用来进行显示当前排队中的顾客
public String toString(){
if(this.size()==0)
return "[Empty]";
StringBuilder result = new StringBuilder();
for(Customer customer :this){
result.append(customer);
}
return result.toString();
}
}
//顾客生产类
//间隔随机然后向队列中加入一位顾客的线程
class CustomerGenerator implements Runnable{
private CustomerLine customerLine; //堵塞队列
private static Random rand = new Random(47);
public CustomerGenerator(CustomerLine customerLine){
this.customerLine = customerLine;
}
public void run(){
try{
while(!Thread.interrupted()){
//线程睡眠随机时间以后,产生一个顾客对象,加入到队列中
TimeUnit.MILLISECONDS.sleep(rand.nextInt(300));
//加入一个服务时间随机的顾客
customerLine.add(new Customer(rand.nextInt(1000)));
}
}catch(InterruptedException ex){
System.out.println(this+" 通过中断异常退出");
}
System.out.println(this+" terminating");
}
}
//出纳员类。负责对队列中的顾客进行服务
//注意其有两种状态:服务顾客或做一些其他的事情
class Teller implements Runnable,Comparable<Teller>{
private static int counter = 0;
private final int id = counter++;
//该Teller服务的顾客队列
private CustomerLine customerLine;
private int customerServed = 0;//已服务的顾客数
//标志眼下是被分配到服务CustomerLine还是做一些其他事
//默认是分配给customerLine
private boolean servingCustomerLine=true;
public Teller(CustomerLine cl){
this.customerLine = cl;
}
//正常情况下会从CustomerLine中取出一个Customer进行服务
//假设被分配到做其他事,则会被挂起
public void run(){
try{
while(!Thread.interrupted()){
Customer customer = customerLine.take();
//睡眠一段时间模拟服务Customer
TimeUnit.MILLISECONDS.sleep(customer.getServiceTime());
synchronized(this){
while(!servingCustomerLine){//被分配做其他事情
wait();
}
}
}
}catch(InterruptedException ex){
System.out.println(this+"通过中断异常退出");
}
System.out.println(this+"Terminating");
}
//调用这种方法意味着该Teller对象被分配去做其他事情
public synchronized void doSomethingElse(){
customerServed = 0;
servingCustomerLine=false; //设定标志。是当前服务线程挂起
}
//被分配到服务到customerLine
public synchronized void serveCustomerLine(){
servingCustomerLine = true;
notifyAll();//通知挂起线程
}
public String toString(){
return "Teller "+id+" ";
}
public String shortString(){
return "T "+id;
}
//按以服务顾客数确定Teller的优先级,给优先队列使用
@Override
public synchronized int compareTo(Teller other){
return customerServed < other.customerServed ?
-1:
(customerServed==other.customerServed ?
0 :1);
}
}
//服务管理和调度Teller的类
//这个TellerManager类是各种活动的中心,它跟踪全部的出纳员以及等待服务的顾客
//从adjustTellerNumber()中能够看到,它会依据实际情况调整服务CustomerLine的
//Teller数量,以期达到最优出纳员的数目。
class TellerManager implements Runnable{
private ExecutorService exec; //负责启动Teller线程
private CustomerLine customerLine;
//按服务顾客数由少到多优先的优先队列,用来进行调度
//每次都取出服务顾客数最少的出纳员来进行服务,以保证公平性。
private PriorityQueue<Teller> workingTellers
= new PriorityQueue<>();
//正在做其他事情的Teller队列
private Queue<Teller> tellersDoingOtherThings
= new LinkedList<Teller>();
private int adjustmentPeriod; //调度时间
private static Random rand = new Random();
public TellerManager(ExecutorService exec,CustomerLine
customerLine,int adjustmentPeriod){
this.exec =exec;
this.customerLine = customerLine;
this.adjustmentPeriod = adjustmentPeriod;
//在构造器中先分配一个Teller进行服务
Teller teller = new Teller(customerLine);
exec.execute(teller);
workingTellers.add(teller);
}
//通过当前customerLine中的顾客数以及正在工作的Teller
//人数的比例关系,来确定是否要加/减Teller的数目
public void adjustTellerNumber(){
//假设customerLine队列过长,则添加服务的Teller
if(customerLine.size()/workingTellers.size()>2){
//假设在做其他事的Teller则从中抽调出人来,否则又一次分配一个Teller
if(tellersDoingOtherThings.size()>0){
Teller teller = tellersDoingOtherThings.remove();
teller.serveCustomerLine();
workingTellers.add(teller);
return;
}
//又一次分配一个Teller
Teller teller = new Teller(customerLine);
exec.execute(teller);
workingTellers.add(teller);
return;
}
//当前Tellers过多时,抽调一些去做其他工作
if(workingTellers.size()>1&&customerLine.size()/workingTellers.size()<2){
reassignOneTeller();
//假设这里仅仅有没有customer须要服务。则仅仅需留下一个Teller
if(customerLine.size()==0){
while(workingTellers.size()>1){
reassignOneTeller();
}
}
}
}
private void reassignOneTeller() {
//从工作队列中取出一个Teller来
Teller teller = workingTellers.poll();
teller.doSomethingElse();//让他去做其他工作
tellersDoingOtherThings.offer(teller);
}
public void run(){
try{
while(!Thread.interrupted()){
TimeUnit.MILLISECONDS.sleep(adjustmentPeriod);
//按当前情况进行动态调整
adjustTellerNumber();
//打印当前的customerLine和workingTeller的情况
//从结果能够看到随着customerLine大小的变化,workingTeller
//的人数也是不断变化的。
System.out.print(customerLine+"{");
for(Teller teller: workingTellers){
System.out.print(teller.shortString()+" ");
}
System.out.println("}");
}
}catch(InterruptedException ex){
System.out.println(this+"通过中断异常退出");
}
System.out.println(this+"terminating");
}
public String toString(){
return "TellerManager";
}
}
public class BankTellerSimulation {
static final int SIZE = 50;//顾客队列的最大长度
static final int PERIOD = 1000;//调整时间间隔
public static void main(String[] args) throws Exception{
ExecutorService exec = Executors.newCachedThreadPool();
CustomerLine customerLine = new CustomerLine(SIZE);
exec.execute(new CustomerGenerator(customerLine));
exec.execute(new TellerManager(exec,customerLine,PERIOD));
System.out.println("Press 'Enter' to exit");
System.in.read();
exec.shutdownNow();
}
}
二.饭店仿真
问题描写叙述:模拟饭店的场景:饭店中有顾客到来以后就会派一个侍者进行服务。然后侍者记录顾客所点的食物以后就提交订单到饭店,然后饭店的厨师取的订单
以后就做好食物然后再由相应的侍者交给顾客。
仿真思路:封装Oder类表示用户的订单,订单中包括了点餐的顾客,相应的侍者和顾客所点的食物;封装Plate类表示装有厨师做好订单上食物的盘子;封装Customer类
表示顾客,每一个顾客会随机选择一种食物然后由服务该顾客的侍者提交订单给饭店,当食物做好以后,顾客吃掉完毕消费过程。封装WaitPerson类表示侍者,侍者一方面帮助服务的顾客提交订单,还有一方面将饭店厨师做好的食物交给相应的顾客;封装Chef表示饭店的厨师,厨师从饭店中取得侍者提交的订单。然后做完当中的食物,然后将相应的Plate提交给该订单相应的WaitPerson。封装Restaurant类表示饭店,饭店中有厨师队列,侍者队列,订单队列,饭店进程中还会每隔一段时间生成一个顾客。
值得注意的是这里事实上牵涉到了多个线程之间协调,可是这些并非通过直接的线程之间的通信来实现的而是通过堵塞队列来实现的。比方说顾客点了食物以后,侍者会提交一份订单,可是这份订单不是给厨师的,而是提交给饭店的订单堵塞队列。然后厨师从这个订单队列中取出订单制作好食物以后并不须要直接通知侍者,而是会提交给侍者的堵塞队列,然后侍者再从它的堵塞队列中取出食物来提交给顾客的堵塞队列,然后顾客在合适的时间从其队列中取出食物来食用。从上面的过程中能够看到使用队列极大地降低了线程间通信的复杂度:任务之间没有直接的相互干涉,而是经由队列来相互发送对象。接收任务将处理对象。将其当成一个消息来对待。而不是向它发送消息。
详细实现代码例如以下:
package lkl;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
class Course{
private static Random rand = new Random();
public static String[] food={"food1","food2","food3","food4"};
public static String randomSelection(){
return food[rand.nextInt(food.length)];
}
}
//封装的订单类
class Order{
private static int counter=0;
private final int id = counter++; //订单唯一的编号
private final Customer customer; //订单相应的顾客
private final WaitPerson waitPerson; //负责该订单的服务员
private final String food; //订单相应的食物
public Order(Customer cust,WaitPerson wait,String food){
this.customer = cust;
this.waitPerson = wait;
this.food = food;
}
//返回订单中的食物
public String item(){
return food;
}
public Customer getCustomer(){
return customer;
}
public WaitPerson getWaitPerson(){
return waitPerson;
}
public String toString(){
return "Order: "+id+"item: "+food+" for: "+customer+" served by: "+waitPerson;
}
}
//装好食物的碟子类
class Plate{
private final Order order; //该碟子相应的订单
private final String food; //该碟子盛放的食物
public Plate(Order order , String food){
this.order = order;
this.food = food;
}
public Order getOrder(){
return order;
}
public String getFood(){
return food;
}
public String toString(){
return food;
}
}
//顾客类
class Customer implements Runnable{
private static int counter = 0;
private final int id = counter++; //顾客id
private final WaitPerson waitPerson ;//服务该顾客的侍者
//表示顾客面前的盘子,在我们的仿真中顾客仅仅会消费一种食物,所以我们使用了
//容量为1的堵塞队列SynchronousQueue来表示其前面的盘子,这个队列每一个put()操作
//后面都必须跟一个take()操作,否则就会堵塞。
private SynchronousQueue<Plate> placeSetting = new SynchronousQueue<Plate>();
public Customer(WaitPerson wait){
this.waitPerson = wait;
}
//将制作完毕的食物提交给顾客,假设前面已经put()过而且
//用户还没有take()则会堵塞
public void deliver(Plate p) throws InterruptedException{
placeSetting.put(p);
}
public void run(){
for(String food: Course.food){
//每次用户都会从菜单中随机选择一种食物
food =Course.randomSelection();
try{
//waitPerson提交用户的订单
waitPerson.placeOrder(this,food);
//表示用户吃掉食物,假设食物还没做好。则take()操作会堵塞
System.out.println(this+" eating "+placeSetting.take());
}catch(InterruptedException ex){
System.out.println("Interrupted");
break;
}
}
System.out.println(this+"finished meal,leaving");
}
public String toString(){
return "Customer "+id+" ";
}
}
//封装的侍者类
class WaitPerson implements Runnable{
private static int counter = 0;
private final int id = counter++; //侍者编号
private final Restaurant restaurant;//侍者所属的饭店
//无界的堵塞队列。用来存放厨师已经完毕的食物
//侍者须要将这些食物送到相应的顾客手上
LinkedBlockingQueue<Plate> filledOrders = new LinkedBlockingQueue<Plate>();
public WaitPerson(Restaurant rest){
this.restaurant = rest;
}
//当用户点了食物以后。侍者提交订单
public void placeOrder(Customer cust, String food){
try{
//向餐馆的订单队列中提交一个新订单
restaurant.orders.put(new Order(cust,this,food));
}catch(InterruptedException ex){
System.out.println("Intrrupted");
}
}
//侍者线程的主要作用是不断的从filledOrders中取出已完毕的食物
//提交给相应的顾客
public void run(){
try{
while(!Thread.interrupted()){
//假设队列为空,则会堵塞
Plate plate = filledOrders.take();
System.out.println(this+"received "+plate+" delivering to "+plate.getOrder().getCustomer());
//将提取的plate提交给相应的顾客
plate.getOrder().getCustomer().deliver(plate);
}
}catch(InterruptedException ex){
System.out.println(this +"Interrupted");
}
}
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 Random rand = new Random(47);
public Chef(Restaurant rest){
restaurant = rest;
}
//厨师线程的主要任务是从饭店的订单队列提取订单,然后完毕当中的食物
//再将完毕以后的plate提交给相应的侍者的filledOrders队列
public void run(){
try{
while(!Thread.interrupted()){
//从订单队列中取出订单,假设没有订单则会堵塞
Order order = restaurant.orders.take();
String food = order.item();//取得该订单所需的食物
//模拟准备这样的食物所需的时间
TimeUnit.MILLISECONDS.sleep(rand.nextInt(500));
Plate plate = new Plate(order,food);
//将完毕的plate交给相应的waitPerson
order.getWaitPerson().filledOrders.put(plate);
}
}catch(InterruptedException ex){
System.out.println(this+"Interrupted");
}
System.out.println(this +"off duty");
}
public String toString(){
return "Chef "+id+" ";
}
}
//饭店类
class Restaurant implements Runnable{
//饭店的侍者队列
private ArrayList<WaitPerson> waitPersons = new ArrayList<WaitPerson>();
//饭店的厨师队列
private ArrayList<Chef> chefs = new ArrayList<Chef>();
private ExecutorService exec = Executors.newCachedThreadPool();
private static Random rand = new Random(47);
//饭店的订单队列
BlockingQueue<Order> orders = new LinkedBlockingQueue<Order>();
public Restaurant(ExecutorService exe,int nWaitPerson,int nChef){
exec = exe;
//预先为饭店分配好侍者和厨师
for(int i=0;i<nWaitPerson;i++){
WaitPerson waitPerson = new WaitPerson(this);
waitPersons.add(waitPerson);
exec.execute(waitPerson);
}
for(int i=0;i<nChef;i++){
Chef chef = new Chef(this);
chefs.add(chef);
exec.execute(chef);
}
}
//饭店任务主要是隔一段时间就产生一个顾客,并为这个顾客分配一个服务的侍者
public void run(){
try{
while(!Thread.interrupted()){
WaitPerson wp = waitPersons.get(rand.nextInt(waitPersons.size()));
Customer c = new Customer(wp);
exec.execute(c);
TimeUnit.MILLISECONDS.sleep(100);
}
}catch(InterruptedException ex){
System.out.println(this+"Interrupted");
}
System.out.println("Restaurant closing");
}
}
public class RestaurantWithQueues {
public static void main(String[] args) throws Exception{
ExecutorService exec = Executors.newCachedThreadPool();
//指定一个五个侍者。2个厨师的饭店
Restaurant restaurant = new Restaurant(exec,5,2);
exec.execute(restaurant);
System.out.println("Press 'Enter' to quit");
System.in.read();
exec.shutdownNow();
}
}
三.汽车装配工厂仿真
问题描写叙述:模拟一条汽车生产线;汽车的生产过程首先是生产底盘。然后在底盘上装配好发动机,动力传动系统,车轮,然后一辆车就生产完毕啦。
仿真思路:封装Car类表示汽车,这个类里同一时候包括了构建汽车的几个方法;封装ChassisBuilder类表示建造底盘的类。封装Assembler类表示组合其他部分的类。这个类
负责调用不同的机器人来组装汽车不同的部分;封装Robot类表示抽象的机器人,每一个机器人都会属于一个RobotPool,同一时候会关联到一个Assembler(组装工作),当工作完毕以后这个联系就会被取消掉;同一时候还会继承Robot实现详细的机器人类。封装RobotPool类来管理全部的Robot,Assember须要机器人则从中调用。
更详细的思路见以下的代码。
详细实现代码例如以下:
package lkl;
import java.util.HashSet;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
//封装Car类表示汽车
class Car1{
private final int id;//汽车编号
//表示開始时汽车各部分都还没组装好
private boolean engine = false ,driveTrain = false, wheels = false;
public Car1(int id){
this.id = id;
}
public Car1(){
id = -1;
}
public synchronized int getId(){
return id;
}
//以下是组装汽车的步骤
//这里通过设定指定的标记为true。表示完毕了相应的步骤
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<Car1>{};
//建造底盘的类
//建好底盘以后就将放入相应的堵塞队列中,供后面的线程使用
class ChassisBuilder implements Runnable{
private CarQueue carQueue; //存放建好底盘的汽车
private int counter = 0;
public ChassisBuilder(CarQueue queue){
carQueue = queue;
}
//线程的主要任务就是生成汽车底盘,放入堵塞队列中
public void run(){
try{
while(!Thread.interrupted()){
TimeUnit.MILLISECONDS.sleep(400);
Car1 c = new Car1(counter++);
System.out.println("ChassisBuilder created "+c);
carQueue.put(c);
}
}catch(InterruptedException ex){
System.out.println("ChassisBuilder interrpted");
}
System.out.println("ChassisBuilder off");
}
}
//组装类,通过调用机器人在建好的底盘上组装其他部分
class Assembler implements Runnable{
//分配记录装好底盘的Car和已经完毕组装号的Car
private CarQueue chassisQueue,finishedQueue;
private Car1 car; //正在组装的Car
private CyclicBarrier barrier = new CyclicBarrier(4);
private RobotPool robotPool;
public Assembler(CarQueue cq,CarQueue fq,RobotPool rt){
chassisQueue = cq;
finishedQueue = fq;
robotPool = rt;
}
public Car1 getCar(){
return car;
}
public CyclicBarrier getBarrier(){
return barrier;
}
//线程的主要任务就是负责调用机器人来组装Car
//注意这里使用了CyclicBarrier来一辆车完毕装好以后才干继续组装下一辆
public void run(){
try{
while(!Thread.interrupted()){
//假设底盘还没有生成则会堵塞
car = chassisQueue.take();
//以下会雇佣各个类型的robot去组装这辆汽车
robotPool.hire(EngineRobot.class,this);
// System.out.println("test");
robotPool.hire(DriveTrainRobot.class,this);
robotPool.hire(WheelsRobot.class,this);
barrier.await(); //假设上面的组装还没完毕,则会堵塞在这里;这样能够保证一辆车组装完以后再组装下一辆车
finishedQueue.put(car); //将组装完毕的车加入队列
}
}catch(Exception ex){
System.out.println("Assemble Interrupted");
}
System.out.println("Assemble off");
}
}
//将组装好的汽车输出进行检查
class Reporter implements Runnable{
private CarQueue carQueue;
public Reporter(CarQueue carQueue){
this.carQueue = carQueue;
}
//线程的主要任务是将组装完毕的汽车打印出来
public void run(){
try{
while(!Thread.interrupted()){
System.out.println(carQueue.take());
}
}catch(InterruptedException ex){
System.out.println("reporter interrupted");
}
}
}
//负责组装工作的机器人类。是一个抽象类
//以下会有各种机器人的详细实现
abstract class Robot implements Runnable{
private RobotPool robotPool;
public Robot(RobotPool pool){
robotPool = pool;
robotPool.add(this); //将自己加入管理池中去
//robotPool.pool.add(this);
}
protected Assembler assembler; //该机器人服务的组装线
//关联到指定的组装线
public Robot assignAssembler(Assembler am){
assembler = am;
return this;
}
private boolean engage = false; //是否在干活
//让机器人干活
public synchronized void engage(){
engage = true;
notifyAll();
}
//由子类实现的抽象方法。每一个子类的行为都不一样
abstract protected void performService();
public void run(){
try{
powerDown(); //假设没有组装线雇佣这个机器人,则线程在此堵塞
while(!Thread.interrupted()){
performService();//干活
assembler.getBarrier().await(); //表示自己的活已经干完
powerDown();
}
}catch(Exception ex){
System.out.println("Exception");
}
}
private synchronized void powerDown() throws Exception{
engage = false;
assembler = null ;//解除和装配线的联系
robotPool.release(this);
while(engage==false){//没有活干时挂起
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.getCar().addEngine();
}
}
//装配传动系统的机器人
class DriveTrainRobot extends Robot{
public DriveTrainRobot(RobotPool pool){
super(pool);
}
protected void performService(){
System.out.println(this+" installing driveTrain");
assembler.getCar().addDriveTrain();;
}
}
//装配轮子的机器人
class WheelsRobot extends Robot{
public WheelsRobot(RobotPool pool){
super(pool);
}
protected void performService(){
System.out.println(this+" installing Wheels");
assembler.getCar().addWheels();
}
}
//集中管理全部的机器人
class RobotPool{
public HashSet<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 Exception{
for(Robot r: pool){//找到合适品种的机器人。假设找不到则等待再递归寻找
if(r.getClass().equals(robotType)){
pool.remove(r);
r.assignAssembler(d);//关联生产线
r.engage();//让机器人干活
return ;
}
}
wait();//当前没有多余的机器人则等待直到有空暇的再递归搜索
hire(robotType,d);//递归
}
public synchronized void release(Robot r){
add(r);
}
}
public class CarBuilder {
public static void main(String[] args) throws Exception{
CarQueue chassisQueue = new CarQueue(),
finishedQueue = new CarQueue();
ExecutorService exec = Executors.newCachedThreadPool();
//依次启动各个机器人。生产线
RobotPool robotPool = new RobotPool();
exec.execute(new EngineRobot(robotPool));
exec.execute(new DriveTrainRobot(robotPool));
exec.execute(new WheelsRobot(robotPool));
exec.execute(new Assembler(chassisQueue,finishedQueue,robotPool));
exec.execute(new Reporter(finishedQueue));
exec.execute(new ChassisBuilder(chassisQueue));
TimeUnit.SECONDS.sleep(7);
exec.shutdownNow();
}
}