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