JAVA多线程模拟火车站售票大厅


实验要求

用多线程设计一个模拟火车站售票大厅的工作情形。火车站有许多售票窗口,有些开放,有些不开放。用多个线程去订票,不能有两个或者以上的线程订到同一个票,当最后一张票卖掉时,再订就异常提示出票卖完了。每个窗口买票需要1-3秒的时间,每次卖票需要打印出买票的时间和买票的窗口名。

一、程序流程图(试验原理)

在这里插入图片描述

二、变量说明

count:当前剩余总票数 place[]:途径站点
num:本次售卖总票数 number[]:相应起始地与目的地之间剩余票数
toplace[]:存储相应起始地与目的地信息

三、功能分析及设计

①火车站有许多窗口,有些开放有些不开放,我们规定一共10个售票口,每次随机开放3-10个,所以我们引入java.util.Random,java.util.Vector,java.util.Collections设计卖票前的vect方法,先得到一个3-10随机开放窗口数open,在创建一个存储随机数的集合,执行open次数的int number = r.nextInt(10) + 1,并利用!v.contains(number)去重得到当前开放窗口,用 Collections.sort(v)排序后显示当前开放窗口。

②用多个线程去订票,不能有两个或者以上的线程订到同一个票,当最后一张票卖掉时,再订就异常提示出票卖完了。每个窗口买票需要1-3秒的时间,每次卖票需要打印出买票的时间和买票的窗口名,所以我们引入java.util.Random,java.text.SimpleDateFormat,java.util.Calendar,用random模拟每次买票需要1-3秒的随机时间,再规定时间格式SimpleDateFormat formatter = new SimpleDateFormat (“yyyy-MM-dd HH:mm:ss”),并将对当前出票时间按设定格式输出formatter.format(calendar.getTime())。起始地与目的地用random随机抽取toplace[]信息,并减少number[]相对应票数。
多线程模拟售票窗口订票则需要重写类的run()方法,改为执行新的sellTicket()方法,实现线程互斥和线程同步,并通过改变线程状态以控制线程调度,每次卖票后当前剩余总票数count减1,用Trainticket t = new Trainticket(num)建立总票数对象,最后创建open数量的线程对象窗口,new Thread(t,“售票点”+v.elementAt(i)).start()建立并运行线程,模拟售票操作。

四、多线程卖票的实现

我们用重写的run()方法调用sellTicket()方法模拟多线程卖票:
①将方法声明为synchronized类型,synchronized是一种同步锁,他的作用是一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞,以保证线程间的互斥,即售票窗口不能同时办理卖票操作。

②进程的阻塞与唤醒,通过this.notifyAll(),this.wait()实现,为防止由于synch ronized锁定造成的单窗口处理所有卖票操作结果,我们将买卖票成功的窗口通过this.wait()休眠,则下一次卖票不会访问上一次的线程,再用this.notifyAll()唤醒所有睡眠线程继续工作直到总票数为0,进行一次票数等于0的判断帮助跳出循环,所有窗口显示票数为0并结束售票。

③模拟卖一张票的过程需要花1-3秒,Thread.sleep(rand.nextInt(2001)+ 1000),让线程休息售票时间模拟引票处理,此时程序休息等待处理结束。

④创建线程对象并开始卖票,用Trainticket t = new Trainticket(num)建立总票数对象,最后创建open数量的线程对象窗口,用for遍历建立并启动相应的线程new Thread(t,“售票点”+v.elementAt(i)).start()模拟售票操作。

每次卖票操作输出包括当前时间,当前线程名Thread.currentThread().getName(),剩余总票数count,以及出发地与目的地,卖完票时显示窗口票数卖完。

五、实验结果及代码

总票数:20张
天津------->北京:2张,北京------->天津:2张,天津------->沈阳:4张,
北京------->沈阳:5张,沈阳------->北京:1张,沈阳------->天津:6张。
总售票口数:10 随机开放[3,10]个售票口
第一次卖票:
在这里插入图片描述
第二次卖票:
在这里插入图片描述

代码:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Random;
import java.util.Vector;

public class Trainticket implements Runnable{
		private int count;
		private String[] place = {"北京","天津","沈阳"};//站点
		private static int num=20;//总票数
		private static int []number={2,2,4,5,1,6};//相应起始地与目的地之间票数
		private static String[] toplace={"天津------->北京",
								  "北京------->天津",
								  "天津------->沈阳",
								  "北京------->沈阳",
								  "沈阳------->北京",
								  "沈阳------->天津",
									};
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd   HH:mm:ss");  
		
	    public Trainticket(int t) {
	        this.count = t;
	    }
	    
		@Override
		public void run() {		//重写run()方法
			this.sellTicket();
		}
		
		private synchronized void sellTicket()
		{
			while (this.count>0)
			{
				this.notifyAll();
				Random rand = new Random();
	        	Calendar calendar = Calendar.getInstance();
				System.out.print(formatter.format(calendar.getTime())+"\t"+Thread.currentThread().getName()+"\t成功出票剩余票数:"+(--count));
				//输出当前的时间,售票口和票数
		        Random r = new Random();
	        	int p=r.nextInt(6);
		        while(number[p]==0){
		        	p=r.nextInt(6);
		        }
		        number[p]--;
				System.out.println("\t"+toplace[p]);
				if (this.count==0)
			    	break;
				try {
					Thread.sleep(rand.nextInt(2001)+ 1000);  //模拟卖一张票的过程需要花1-3秒
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
	    	System.out.println(Thread.currentThread().getName()+"票已售完");
		}
		
		private static void vect(Vector<Integer> v,int m,int n)
		{
	        Random r = new Random();
	        // 创建一个存储随机数的集合
	        int open=r.nextInt(m)+n;
	        int count = 0;
	        while (count < open) {
	            int number = r.nextInt(10) + 1;//一共10个窗口,开放指定数量
	            // 判断number是否在集合中存在
	            if (!v.contains(number)) {
	                // 不在集合中,就添加
	                v.add(number);
	                count++;
	            }
	        }
	        Collections.sort(v);
			System.out.print("开放的售票口为:");
			for(int i=0;i<v.size();i++){
				System.out.print(" 售票点"+v.elementAt(i)+" ");
			}
			System.out.println();
		}
		
		public static void main(String[] args) {
			// TODO Auto-generated method stub
	        Vector<Integer> v = new Vector<Integer>();
			vect(v,8,3);//开放3-10个窗口
			//创建线程类对象
			Trainticket t = new Trainticket(num);//一共20张票
			//启动线程
			for(int i=0;i<v.size();i++){
				new Thread(t,"售票点"+v.elementAt(i)).start();
			}
		}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值