import java.util.*;public classBank {//定义服务时间常量,后面要用。
public static final long SHORTEST_SEVICE_TIME = 1000;public static final long LONGEST_SEVICE_TIME = 10000;public static final long BETWEEN_SEVICE_TIME = LONGEST_SEVICE_TIME -SHORTEST_SEVICE_TIME;public static voidmain (String[] args){//定义3个队列。因为是先进先出,所以用到LinkedList效率会比较好,用Collections.synchronizedList让线程安全。
List comm = Collections.synchronizedList (new LinkedList());
List exp = Collections.synchronizedList (new LinkedList());
List vip = Collections.synchronizedList (new LinkedList());//建立银行窗口
BankWindow comm1 = new BankWindow(1,WindowType.COMM);
BankWindow comm2= new BankWindow(2,WindowType.COMM);
BankWindow comm3= new BankWindow(3,WindowType.COMM);
BankWindow comm4= new BankWindow(4,WindowType.COMM);
BankWindow exp5= new BankWindow(5,WindowType.EXP);
BankWindow vip6= new BankWindow(6,WindowType.VIP);//银行窗口多线程开启
FuWuGuKe f1 = newFuWuGuKe(comm1,comm, exp, vip);
FuWuGuKe f2= newFuWuGuKe(comm2,comm, exp, vip);
FuWuGuKe f3= newFuWuGuKe(comm3,comm, exp, vip);
FuWuGuKe f4= newFuWuGuKe(comm4,comm, exp, vip);
FuWuGuKe f5= newFuWuGuKe(exp5,comm, exp, vip);
FuWuGuKe f6= newFuWuGuKe(vip6,comm, exp, vip);
Thread t1= newThread(f1);
Thread t2= newThread(f2);
Thread t3= newThread(f3);
Thread t4= newThread(f4);
Thread t5= newThread(f5);
Thread t6= newThread(f6);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();//队列就不用额外的线程了,直接放在主线程里。
while (true){
DuiLie.shengChengDuiLie(comm, exp, vip);
mySleep((long)(Math.random()*900) + 200);
}
}//定义了一个线程休眠的方式,不然要try catch好多遍。
public static void mySleep(longhaomiao){try{
Thread.sleep(haomiao);
}catch(Exception e){
}
}
}//服务顾客这个类准备用多线程
class FuWuGuKe implementsRunnable{privateBankWindow bw;private Listcomm;private Listexp;private Listvip;//创建对象的时候把bankwindow传进来,在run里使用对应对象的方法。
public FuWuGuKe(BankWindow bw, List comm, List exp, Listvip){this.bw =bw;this.comm =comm;this.exp =exp;this.vip =vip;
}public voidrun(){while(true){//对象(bankwindow)先服务自己类型 的顾客
bw.service(bw.getType(), comm, exp, vip);
}
}
}classBankWindow{//定义窗口的id和类型,以及名字
private intid;privateWindowType type;privateString windowName;//构造函数,设置窗口id和类型。
BankWindow(intid, WindowType type){this.id =id;this.type =type;
windowName= "第"+id+"号"+type +"窗口";
}//返回对象的窗口类型的方法
publicWindowType getType(){return this.type;
}//服务顾客的方法。因为:要处理对应类型的顾客,还有可能使用到3个类型的队列,所以全部当参数传入
public voidservice (WindowType type, List comm, List exp, List vip){intcustomID;longserviceTime;
System.out.println(windowName+"正在获取" + type + "客户");if (type ==WindowType.COMM){if (comm.size() != 0){//普通类型的队列如果不为空,则处理普通顾客//处理队列中的第一个客户,把客户的ID给customID,在打印语句中使用,下同。
customID = (int)comm.remove(0);
System.out.println(windowName+"获取到客户:"+customID+"普通客户");//计算服务时间(单位毫秒),赋值给serviceTime,在打印语句中使用,下同。
serviceTime = Bank.SHORTEST_SEVICE_TIME + (long)(Math.random() *Bank.BETWEEN_SEVICE_TIME) ;//调用Bank类中的mySleep方法,避免多次写try catch下同。
Bank.mySleep(serviceTime);
System.out.println(windowName+":"+customID+"普通客户服务完毕,服务时间:"+ serviceTime +"毫秒");
}else{//没有普通顾客则休息
System.out.println(windowName+":没有待服务的普通客户,休息。");
Bank.mySleep(1000);
}
}else if (type == WindowType.EXP){//快速类型的队列如果不为空,则处理快速顾客
if (exp.size() != 0){
customID= (int)exp.remove(0);
System.out.println(windowName+"获取到客户:"+customID+"快速客户");
serviceTime=Bank.SHORTEST_SEVICE_TIME;//快速顾客服务时间为最短服务时间。
Bank.mySleep(serviceTime);
System.out.println(windowName+":"+customID+"快速客户服务完毕,服务时间:"+ serviceTime +"毫秒");
}else {//没有快速类型的顾客,则处理普通顾客。有点递归的味道,不过由于处理普通顾客的方法会休息并结束,所以不是递归。下同
System.out.println(windowName+"没有获取到快速客户;尝试获取普通客户");
service(WindowType.COMM, comm, exp, vip);
}
}else if (type == WindowType.VIP){//贵宾类型的队列如果不为空,则处理贵宾顾客
if (vip.size() != 0){
customID= (int)vip.remove(0);
System.out.println(windowName+"获取到客户:"+customID+"贵宾客户");
serviceTime= Bank.SHORTEST_SEVICE_TIME + (long)(Math.random() *Bank.BETWEEN_SEVICE_TIME) ;
Bank.mySleep(serviceTime);
System.out.println(windowName+":"+customID+"贵宾客户服务完毕,服务时间:"+ serviceTime +"毫秒");
}else{//没有类型类型的顾客,则处理普通顾客。
System.out.println(windowName+"没有获取到贵宾客户;尝试获取普通客户");
service(WindowType.COMM, comm, exp, vip);
}
}
}
}//生成队列的类
classDuiLie{//定义了静态队列编号,随着类的加载而加载,
private static Integer commCust=0;private static Integer expCust=0;private static Integer vipCust=0;//无法new对象,没有意义。
privateDuiLie(){};//每次产生一个随机数,根据随机数的大小,往对应的队列里加入对应编号的成员。
public static voidshengChengDuiLie(List comm, List exp, List vip){double randNum =Math.random();//三种顾客的比例为6:3:1,所以分为用0.6和0.9把随机数分为3种类型。
if (randNum < 0.6){
commCust++;
comm.add(commCust);
System.out.println(commCust+"号普通用户抵达银行");
}else if(randNum < 0.9){
expCust++;
exp.add(expCust);
System.out.println(expCust+"号快速用户抵达银行");
}else{
vipCust++;
vip.add(vipCust);
System.out.println(vipCust+"号贵宾用户抵达银行");
}
}
}//定义一个枚举,我也不是很懂。
enumWindowType{
COMM, EXP, VIP;publicString toString(){switch (this){caseCOMM:return "普通";caseEXP:return "快速";caseVIP:return "贵宾";
}return "";
}
}