Topic: 模拟火车站售票的情形,有些难。对多线程感兴趣的同志进来看看 |
Print this page |
1.模拟火车站售票的情形,有些难。对多线程感兴趣的同志进来看看 | Copy to clipboard |
Posted by: letsgome Posted on: 2006-01-12 18:47 最近学了JAVA的多线程,想编一个模拟火车站售票的JAVA程序,但是总是在实时显示每个售票窗口的队列时有很大的错误(就是人多,需要排队的时候,每个顾客的ID总是显示相同),不知如何解决?望高手指教。 思路:火车站有许多售票窗口,有些开放,有些不开放。顾客进入火车站售票厅后,到某个售票先排队,排到了就办理业务,然后离去。 为了好控制,用按钮来增加顾客,由人自己来做添加。 代码如下: /*模拟火车站售票的情形 分五个类: SimulateRailwayStation:是具体运行类; RailwayStation:火车站类 Agent类:代表火车站售票窗口类; Customer类:顾客类; List类:存储类 */ import java.util.Date; import java.awt.*; import java.awt.event.*; public class SimulateRailwayStation extends Frame implements ActionListener { protected static final int NUM_AGANTS=10;//表示火车站有10个售票窗口 protected static final int NUM_INITIAL_AGANTS=6;//表示目前正在售票的窗口6个 protected static final int BUSINESS_DELAY=6000;//表示每个窗口办理售票业务的时间 protected static final int MAX_TRAIN_NUM=10;//表示有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);addcus.addActionListener(this); buttons.add(delcus);delcus.addActionListener(this); buttons.add(addagent);addagent.addActionListener(this); buttons.add(delagent);delagent.addActionListener(this); addWindowListener(new WindowCloser()); setLayout(new BorderLayout()); add("North",railwaystation); add("South",buttons); setSize(500,200); validate(); pack();show(); railwaystation.start(); } public void actionPerformed(ActionEvent ae) { if(ae.getSource()==addcus) { railwaystation.generateCustomer(); } else if(ae.getSource()==delcus) { //暂时未实现 } else if(ae.getSource()==addagent) { //暂时未实现 } else if(ae.getSource()==delagent) { //暂时未实现 } } public static void main(String[] args) { SimulateRailwayStation smlt=new SimulateRailwayStation(); } } class RailwayStation extends Panel implements Runnable { 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); add("North",new Label(title)); } public void start()//begin work { if(thread==null) { thread =new Thread(this); thread.start(); } } 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 updateDisplay() { int totalSize=0; for(int i=0;i<numAgents;i++) { 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()+"正在等待]"); else labelAgent[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 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) { int index=0; for(int i=0;i<numAgents;i++) { if(agent[i].getCusCountOfQueue()<agent[index].getCusCountOfQueue()) { index=i; } } agent[index].joinNewCustomer(new Customer()); } } public void run() { while (true) { this.updateDisplay(); } } } 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)//new Agent { this.ID=ID; } public void start()//begin work { if(thread==null) { running=true; thread =new Thread(this); thread.start(); } } public void halt()//stop work { running=false; } public int getCIdOfHandling()//获得正在办理业务的顾客ID { 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);//顾客办理后离开。 RailwayStation.numCustomerServered+=1;//服务顾客数+1 } else { handlingCId=0; } } catch(InterruptedException ie) { System.out.println("Teller Exception: "+ie); } } } } class Customer { private Date created;//顾客开始排队的时间 private static int cId;//顾客ID,每个顾客都有唯一的ID,不能重复 private int customerwilling=0;//顾客购买票务的意愿,比如去哪里,班次等. public Customer() { customerwilling=(int)(Math.random()*10+1);//顾客进入车站时就已经想好了买什么票,并且是火车站能够提供的. created=new Date(); ++cId; System.out.print("new Customer"+cId+","); } public int getCustomerId()//获得顾客ID { return cId; } public int getCustomerWilling()//获得顾客买票意愿 { return customerwilling; } public long getWaitTime(Date now)//获得顾客从进入火车站到离开窗口的时间 { return now.getTime()-created.getTime(); } } class List //是一个队列容器,每个服务的窗口都有一个,顾客总是先进入这个队列容器后,再进行窗口的业务处理. { private int maxItems=100;//队列最大100人 private int numItems=0; private int ID=-1; private Object[] list=null; public List() { list=new Object[maxItems]; } public List(int maxItems) { this.maxItems=maxItems; list=new Object[this.maxItems]; } public void add(Object obj)//在队列中增加人 { list[numItems++]=obj; } public void delete(int pos)//在有人离开队列 { for(int i=pos+1;i<numItems;i++) { list[i-1]=list[i]; } numItems--; } public Object get(int pos)//得到队列中指定的人 { return list[pos]; } public int getSize()//队列中的人数 { return numItems; } public boolean isFull()//队列是否满了 { return (numItems>=maxItems); } } |
2.Re:模拟火车站售票的情形,有些难。对多线程感兴趣的同志进来看看 [Re: letsgome] | Copy to clipboard |
Posted by: heaven Posted on: 2006-01-14 23:35 先写个不带GUI的,如果需要再加上服务,这两天维护一堆破烂,逻辑代码和各种UI组件混在一起,烦死了 |
3.Re:模拟火车站售票的情形,有些难。对多线程感兴趣的同志进来看看 [Re: letsgome] | Copy to clipboard |
Posted by: allenchen Posted on: 2006-01-16 23:42 Customer类的id编号错误,不应用static。 private int cId;// 顾客ID,每个顾客都有唯一的ID,不能重复 private static int idCounter = 1; private int customerwilling = 0;// 顾客购买票务的意愿,比如去哪里,班次等. public Customer() { customerwilling = (int) (Math.random() * 10 + 1);// 顾客进入车站时就已经想好了买什么票,并且是火车站能够提供的. created = new Date(); cId = idCounter; idCounter++; System.out.print("Customer [" + cId + "] : " + SimulateRailwayStation.train_num[customerwilling - 1]); } |
4.Re:模拟火车站售票的情形,有些难。对多线程感兴趣的同志进来看看 [Re: allenchen] | Copy to clipboard |
Posted by: jeason1914 Posted on: 2006-04-10 13:28 在多线程里最好对公共数据采用同步机制 |
Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1 客服电话 18559299278 客服信箱 714923@qq.com 客服QQ 714923 |