Thinking in Java---多线程仿真:银行出纳员仿真+饭店仿真+汽车装配工厂仿真

多线程一个非常有意思的作用就是用于仿真,这篇博客就会结合几个仿真实例来综合运用一下前面所学的多线程并发知识。

一.银行出纳员仿真

问题描写叙述:银行会有非常多来办业务的顾客,他们会排队等待服务;对于银行方面他们派出出纳员来服务顾客,假设排队的顾客数量过多,银行就会添加

出纳员的数量,假设顾客的数目过少。则降低出纳员的数目;总之要保持一个平衡。

仿真思路:封装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();
}
}
时间: 07-09

Thinking in Java---多线程仿真:银行出纳员仿真+饭店仿真+汽车装配工厂仿真的相关文章

第12篇-JAVA 多线程

第12篇-JAVA 多线程 每篇一句 :不要只看到艰难,要看艰难后面的胜利 初学心得: 敢于尝试,就等于你已经向成功迈出了第一步 (笔者:JEEP/711)[JAVA笔记 | 时间:2017-04-20| JAVA 多线程 ] 1.进程与线程 1.什么是进程 程序是指令和数据的有序的集合,其本身没有任何运行的含义,是一个静态的概念 进程是一个具有一定独立功能的程序,一个实体 几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程 当一个程序运行时,内部可

java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提

这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在运行,锁加在哪一块代码 那么我们要思考的地方有:1.知道我们写的哪些是多线程代码 2.明确共享数据 3.明确多线程运行的代码中哪些语句是操作共享数据的.. 4.要确保使用同一个锁. 下面的代码:需求:两个存户分别往银行存钱,每次村100块,分三次存完. class bank{ private int

Java 多线程(五) 多线程的同步

Java 多线程(五) 多线程的同步 为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资源的第一个线程为其加上锁以后,其他线程便不能再使用那个资源,除非被解锁. 程序实例 用一个取钱的程序例子,来说明为什么需要引入同步. 在使用同步机制前,整体程序如下: public class FetchMoneyTest { public static void main(Stri

JAVA多线程之中断机制(stop()、interrupted()、isInterrupted())

一,介绍 本文记录JAVA多线程中的中断机制的一些知识点.主要是stop方法.interrupted()与isInterrupted()方法的区别,并从源代码的实现上进行简单分析. JAVA中有3种方式可以终止正在运行的线程 ①线程正常退出,即run()方法执行完毕了 ②使用Thread类中的stop()方法强行终止线程.但stop()方法已经过期了,不推荐使用 ③使用中断机制 线程正常退出没有什么东东,中断机制下面详细介绍,先看下stop()方法的源代码,关键是源代码上的注释.它解释了为什么s

java多线程并发概览

一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. "同时"执行是人的感觉,在线程之间实际上轮换执行. 二.Java中的线程 在J

Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例

概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3534050.html Semaphore简介 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可

从JAVA多线程理解到集群分布式和网络设计的浅析

对于JAVA多线程的应用非常广泛,现在的系统没有多线程几乎什么也做不了,很多时候我们在何种场合如何应用多线程成为一种首先需要选择的问题,另外关于java多线程的知识也是非常的多,本文中先介绍和说明一些常用的,在后续文章中如果有必要再说明更加复杂的吧,本文主要说明多线程的一下几个内容: 1.在应用开发中什么时候选择多线程? 2.多线程应该注意些什么? 3.状态转换控制,如何解决死锁? 4.如何设计一个具有可扩展性的多线程处理器? 5.多线程联想:在多主机下的扩展-集群? 6.WEB应用的多线程以及

java多线程心得

多并发的时候,在什么情况下必须加锁?如果不加锁会产生什么样的后果. 加锁的场景跟java的new thread和Runnable的关系是什么? 看看java的concurrentMap源码. 还有spring 的web.xml启动执行源码 spring aop http://www.cnblogs.com/FDROSE1001/p/3661895.html activemq的本质是什么? java的jms hibernate由配置文件映射到实体类的本质是什么? java反射 spring aop

Rhythmk 一步一步学 JAVA (21) JAVA 多线程

1.JAVA多线程简单示例 1.1 .Thread  集成接口 Runnable 1.2 .线程状态,可以通过  Thread.getState()获取线程状态: New (新创建) Runnable (可以运行) Blocked  (被阻塞) Waiting  (等待) Timed waiting (计时等待) Terminated  (被终止) ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

(转载)Java多线程入门理解

转载出处http://blog.csdn.net/evankaka 写在前面的话:此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢?如果你觉得此文很简单,那推荐你看看Java并发包的的线程池(Java并发编程与技术内幕:线程池深入理解),或者看这个专栏:Java并发编程与技术内幕.你将会对Java里头的高并发场景下的线程有更加深刻的理解. 目录(?)[-] 一扩展javalangThread类 二实现javalan