/*项目:用多线程设计一个模拟火车站售票大厅的工作情形。
问题描述:火车站有许多售票窗口,有些开放,有些不开放。
顾客进入火车站售票厅后,到某个售票窗口排队等候,排到了就办理业务,然后离去。
如图2.1所示。
*//**共有五个类:*SimulateRailwayStation:具体运行主类;*RailwayStation:火车站售票大厅类*Agent类:代表火车站售票窗口类;*Customer类:顾客类;*List类:存储类*/import java.util.Date;import java.awt.*;import java.awt.event.*;public class SimulateRailwayStation extends Frame implements ActionListener{//预设火车站售票大厅有10个售票窗口protected static final int NUM_AGANTS=10;//预设目前正在售票的窗口为6个protected static final int NUM_INITIAL_AGANTS=6;//设置每个窗口办理售票业务的时间protected static final int BUSINESS_DELAY=6000;//设置有10辆火车的座位可以出售protected static final int MAX_TRAIN_NUM=10;//设置每个窗口从一个顾客完成到下一个顾客开始的时间间隔protected static final int MAX_NO_CUSTOMERS=200;//定义按钮,手动添加顾客。
private Button addcus=new Button("添加顾客");//定义按钮,模拟顾客自己离开private Button delcus=new Button("顾客离去");//定义按钮,增加售票窗口private Button addagent=new Button("增加售票窗口");//定义按钮,关闭售票窗口private Button delagent=new Button("关闭售票窗口");//10辆火车班次的信息protected static String[] train_num={"南京->北京,46次","南京->上海,34次","南京->福州,231次","南京->杭州,65次","南京->武汉,112次","南京->成都,77次","南京->天津,21次","南京->徐州,134次","南京->乌鲁目齐,335次","南京->合肥,456次"}; //与上面的信息对应的每辆火车的票务信息protected static int[] tickets={50,70,50,50,50,120,60,100,50,50};//实例化火车站售票大厅类private RailwayStation railwaystation=new RailwayStation();//建立窗体适配器,能关闭窗口private class WindowCloser extends WindowAdapter{public void windowClosing(WindowEvent we){railwaystation.stop();System.exit(0);}}//构造方法,完成界面初始化public SimulateRailwayStation(){super("Simulation RailwayStation");//设置面板Panel buttons=new Panel();buttons.setLayout(new FlowLayout());//在面板中添加按钮buttons.add(addcus);buttons.add(delcus);buttons.add(addagent);buttons.add(delagent);//对按钮设置监听addcus.addActionListener(this);delcus.addActionListener(this);addagent.addActionListener(this);delagent.addActionListener(this);//对窗体适配器设置监听addWindowListener(new WindowCloser());setLayout(new BorderLayout());add("North",railwaystation);add("South",buttons);setSize(500,200);validate();pack();show();//调用火车站售票大厅类的start()方法,开始售票工作railwaystation.start();}public void actionPerformed(ActionEvent ae){if(ae.getSource()==addcus){//新增顾客railwaystation.generateCustomer();}else if(ae.getSource()==delcus){}else if(ae.getSource()==addagent){//增加售票窗口railwaystation.addAgent();}else if(ae.getSource()==delagent){//关闭服务窗口railwaystation.retireAgent();}}public static void main(String[] args){SimulateRailwayStation smlt=new SimulateRailwayStation();}}/* 火车站售票大厅类 */class RailwayStation extends Panel implements Runnable{//定义售票窗口数组Agent[]protected Agent[] agent=new Agent[SimulateRailwayStation.NUM_AGANTS];protected Label[] labelAgent=new Label[SimulateRailwayStation.NUM_AGANTS]; protected Label labelQueue=new Label("正在等待的顾客数:0");protected Label labelServed=new Label("已经服务的顾客数:0");//定义可以进行售票服务的窗口protected int numAgents=SimulateRailwayStation.NUM_INITIAL_AGANTS;//定义存放已服务过的顾客数public static int numCustomerServered=0;private Thread thread=null;public RailwayStation(){setup("各窗口实时状态显示:");}//显示各售票窗口的实时工作状态private void setup(String title){//定义售票窗口的工作状态面板Panel agentPanel=new Panel();agentPanel.setLayout(new GridLayout(SimulateRailwayStation.NUM_AGANTS,1)); //各售票窗口的工作状态for(int i=0;i<SimulateRailwayStation.NUM_AGANTS;i++){if(i<numAgents){labelAgent[i]=new Label("窗口"+(i+1)+":空闲中...");agentPanel.add(labelAgent[i]);//实例化售票窗口agent[i]=new Agent(i);//售票窗口开始售票服务agent[i].start();}else{labelAgent[i]=new Label("窗口"+(i+1)+":暂停服务!");agentPanel.add(labelAgent[i]);}}//定义顾客候票情况面板Panel otherPanel=new Panel();otherPanel.setLayout(new GridLayout(2,1));otherPanel.add(labelQueue);otherPanel.add(labelServed);setLayout(new BorderLayout());//显示各售票窗口的工作状态安排在下部add("South",agentPanel);//显示顾客候票状况安排在中部add("Center",otherPanel);//显示调用本方法 setup()的参数安排在上部add("North",new Label(title));}//开始工作public void start(){if(thread==null){thread =new Thread(this);//启动线程thread.start();}}//线程,调用显示实时售票状况的updateDisplay()方法public void run(){while (true){this.updateDisplay();}}//实时处理售票的状况public void updateDisplay(){//定义在本窗口等候的顾客数int totalSize=0;//对可以服务的窗口进行循环for(int i=0;i<numAgents;i++){//getCIdOfHandling()方法为正在办理业务的顾客编号if(agent[i].getCIdOfHandling()!=0){//统计在本窗口等候的顾客数totalSize+=agent[i].getCusCountOfQueue();String s="窗口"+(i+1)+":正在办理顾客"+agent[i].getCIdOfHandling()+"业务"; //显示在本窗口等候的顾客数if(agent[i].getCusCountOfQueue()>0)labelAgent[i].setText(s+"["+agent[i].getCusOfQueue()+"正在等待]");elselabelAgent[i].setText(s);}else{labelAgent[i].setText("窗口"+(i+1)+":空闲中...");}}for(int i=numAgents;i<SimulateRailwayStation.NUM_AGANTS;i++) labelAgent[i].setText("窗口"+(i+1)+":暂停服务!");labelQueue.setText("正在等待的顾客数:"+totalSize);labelServed.setText("已经服务的顾客数:"+numCustomerServered); }//火车站售票窗口关闭public void stop(){thread=null;for(int i=0;i<numAgents;i++){//停止售票服务agent[i].halt();}}//添加窗口public void addAgent(){if(numAgents<SimulateRailwayStation.NUM_AGANTS){agent[numAgents]=new Agent(numAgents);agent[numAgents].start();numAgents++;}}//关闭窗口,该方法暂时没有使用public void retireAgent(){if(numAgents>1){agent[numAgents-1].halt();numAgents--;}}//接待顾客的方法public void generateCustomer(){//所有工作窗口的队列中,至少有一个顾客在排队时为真.boolean allAgentQueueHasOne=true;/* 如果所有正在工作窗口的队列中至少有一个顾客在排队,就把新顾客添加到队列最少的那个队.否则,就把顾客添加到没有业务处理的窗口中.*///对可以服务的窗口进行循环for(int i=0;i<numAgents;i++){//如果本窗口队列中没有顾客if(agent[i].getCusCountOfQueue()==0 && agent[i].getCIdOfHandling()==0) {//添加新顾客agent[i].joinNewCustomer(new Customer());allAgentQueueHasOne=false;break;}}//如果所有工作窗口都有顾客在等候if(allAgentQueueHasOne){//定义变量index存放最少等候顾客数的窗口编号int index=0;//对可以服务的窗口进行循环for(int i=0;i<numAgents;i++){if(agent[i].getCusCountOfQueue()<agent[index].getCusCountOfQueue()) {(见教材)}}//往最少顾客的窗口加新顾客agent[index].joinNewCustomer(new Customer());}}}/*火车站售票窗口类 */class Agent extends Panel implements Runnable{//窗口开放标志private boolean running =false;private int ID=-1;private int numCustomers=0;private int handlingCId=0;//该窗口中排队的顾客private List customersofqueue=new List(); //该窗口中已办理的顾客private List customersofhandled=new List(); private Label labelHandling=new Label();private Label labelThisQueue=new Label();private Thread thread=null;//构造方法,定义售票窗口编号public Agent(int ID){(见教材)}// 售票窗口开始售票服务public void start(){if(thread==null){running=true;thread =new Thread(this);//启动线程thread.start();}}//停止售票服务public void halt(){running=false;}//获得正在办理业务的顾客IDpublic int getCIdOfHandling(){return handlingCId;}//从本窗口的队列中获得将要服务的顾客public Customer requestCustomerFor(){if(customersofqueue.getSize()>0){Customer c=(Customer)customersofqueue.get(0);customersofqueue.delete(0);return c;}else{return null;}}//本窗口已办理业务的顾客数public int getCusCountOfHandled(){return numCustomers;}//本窗口已办理业务的顾客列表public String getCusOfHandled(){if(customersofhandled.getSize()>0){StringBuffer sbuf=new StringBuffer();sbuf.append("顾客");for(int i=0;i<customersofhandled.getSize();i++){sbuf.append(((Customer)customersofhandled.get(i)).getCustomerId()); if(i!=customersofhandled.getSize()-1)sbuf.append(",");}return sbuf.toString();}else{return new String("");}}//在窗口的队列中添加新顾客public synchronized void joinNewCustomer(Customer c){if(!customersofqueue.isFull()){customersofqueue.add(c);System.out.println("join to agent"+(this.ID+1));}}//获得本窗口的队列中的顾客列表public synchronized String getCusOfQueue(){if(customersofqueue.getSize()>0){StringBuffer sbuf=new StringBuffer();sbuf.append("Customer");for(int i=0;i<customersofqueue.getSize();i++){sbuf.append(((Customer)customersofqueue.get(i)).getCustomerId()); if(i!=customersofqueue.getSize()-1)sbuf.append(",");}return sbuf.toString();}else{return new String("");}}//获得本窗口的队列中的顾客数public int getCusCountOfQueue(){return customersofqueue.getSize();}//本窗口队列中的顾客未办理业务离去public void CustomerLeft(){if(customersofqueue.getSize()>0)customersofqueue.delete(customersofqueue.getSize()-1);}//顾客办理完业务离去public void releaseCustomer(Customer c){numCustomers++;customersofhandled.add(c);}//本窗口在不断的处理业务public void run(){while (running){try{thread.sleep((int)(Math.random()*SimulateRailwayStation.MAX_NO_CUSTOMERS)+1000); Customer customer=requestCustomerFor();//获得服务的顾客if(customer!=null){handlingCId=customer.getCustomerId();//获得顾客ID//办理业务时间:主要是询问等thread.sleep((int)(Math.random()*SimulateRailwayStation.BUSINESS_DELAY)/2); synchronized(this){//检索对应的票务信息for(int i=0;i<SimulateRailwayStation.train_num.length;i++){if(customer.getCustomerWilling()==i+1)SimulateRailwayStation.tickets[i]--;//对应票数减一}}//办理业务时间:打印票、交钱等thread.sleep((int)(Math.random()*SimulateRailwayStation.BUSINESS_DELAY)/2); releaseCustomer(customer);//顾客办理后离开。