黑马程序员技术交流社区
标题:
关于 银行业务调度系统
[打印本页]
作者:
qqwwdr
时间:
2014-3-2 13:40
标题:
关于 银行业务调度系统
我用 等待唤醒机制 重写 了 银行业务调度系统,
有时候会出现这种bug:
当VIP窗口或者是快速窗口 对应的VIP客户或者是快速业务客户还有的时候,VIP窗口或者是快速窗口跑去处理普通客户去了,
自己分析了一晚上也没找到原因,求助高手解惑
代码如下:
主类:
package cn.itheima.wxn.bankQueue;
import java.util.*;
public class BankQueue {
//三个队列模拟三种客户排队
public static List<Integer> common = new ArrayList<Integer>();
public static List<Integer> express = new ArrayList<Integer>();
public static List<Integer> vip = new ArrayList<Integer>();
public static void main(String[] args) {
//将三个队列转换成线程安全
common = Collections.synchronizedList(common);
express = Collections.synchronizedList(express);
vip = Collections.synchronizedList(vip);
//开启为三个队列加入客户的线程
new Thread(new CustomerGenerative(common, express, vip)).start();
//开启为4个普通窗口的线程
for (int i = 1; i < 5; i++) {
new Thread(new WindowService(common, express, vip,WindowType.COMMON, i)).start();
}
//开启快速窗口的线程
new Thread(new WindowService(common, express, vip, WindowType.EXPRESS,5)).start();
//开启vip窗口的线程
new Thread(new WindowService(common, express, vip, WindowType.VIP, 6)).start();
}
}
复制代码
客户编码产生器:
package cn.itheima.wxn.bankQueue;
import java.util.List;
import java.util.Random;
//产生客户,按6:3:1的几率产生客户
class CustomerGenerative implements Runnable {
private List<Integer> common;
private List<Integer> express;
private List<Integer> vip;
//构造方法,接收3个模拟队列的集合
CustomerGenerative(List<Integer> list1, List<Integer> list2,
List<Integer> list3) {
this.common = list1;
this.express = list2;
this.vip = list3;
}
@Override
public void run() {
int commonCount = 0; //统计总的普通客户的人数
int expressCount = 0; //统计中的快速客户的人数
int vipCount = 0; //统计总的vip客户的人数
Integer num = 0; //递增的索引,可以表示总的客户的人数
Random r = new Random();
while (true) {
//每当有10的倍数个客户进入的时候,输出统计信息
if(num%10 == 0){
System.out.println("=====查看排队用户信息=======");
System.out.println(this.common + "全部的普通客户有:" + commonCount + "人");
System.out.println( this.express+ "全部的快速客户有:" + expressCount + "人");
System.out.println( this.vip+ "全部的VIP客户有:" + vipCount + "人");
System.out.println("=======================");
}
num++;
//进程睡眠2秒
try {
Thread.sleep(r.nextInt(2000));
} catch (Exception ex) {
ex.printStackTrace();
}
//flag用于判断是添加那种类型的客户
int flag = r.nextInt(10); //取0~10之间的随机数,随机数是0~5,是普通客户;6~8是快速客户;9是vip客户
if (flag < 6) {
common.add(num);
System.out.println("======>" +num + "号普通客户等待");
commonCount++;
synchronized (common) {
this.common.notifyAll();
}
} else if (flag >= 6 && flag < 9) {
express.add(num);
System.out.println("======>" +num + "号快速客户等待");
expressCount++;
synchronized (express) {
this.express.notifyAll();
}
} else {
vip.add(num);
System.out.println("======>" + num + "号VIP客户等待");
vipCount++;
synchronized (vip) {
this.vip.notifyAll();
}
}
}
}
}
复制代码
窗口类代码:
package cn.itheima.wxn.bankQueue;
import java.util.List;
import java.util.Random;
class WindowService implements Runnable {
private List<Integer> common;
private List<Integer> express;
private List<Integer> vip;
private String name;
private WindowType type;
//无参构造方法
WindowService() {}
//构造方法
WindowService(List<Integer> common, List<Integer> express,
List<Integer> vip, WindowType type, int count) {
//接收三个模拟队列的集合
this.common = common;
this.express = express;
this.vip = vip;
//指定本窗口的类型
this.type = type;
//指定窗口的名称
this.name = count + "号" + this.type + "窗口";
}
/**
* @see 窗口的服务方法
*@param list:方法接收一个模拟队列的集合,
*@param radix: 服务的时间等级, 这个等级没有限制,自己微调,表示服务时间的长短
@return false,表示没有客户,返回true表示已经服务完客户
*/
public boolean serveCustomer(List<Integer> list, int radix) {
Random r = new Random();
Integer num = null; //接收从集合中取出的客户的编号
//同步代码块,从集合中取元素的功能,
synchronized (list) {
//如果集合中没有元素的情况下,窗口要么等待,要么接收其他客户队列的服务请求
while (list == null || list.isEmpty() || (num = list.remove(0)) == null) {
//如果本窗口不是普通窗口并且客户队列不是普通队列,返回false
if (!this.type.equals(WindowType.COMMON) && list != this.common){
System.out.println("\t~!@#$%^&**()" + this.name + "没能获取相应客户");
return false;
}
//窗口等待
try {
System.out.println("\t[" + this.name + "等待客户******");
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//根据取出的编号得到客户的名称
StringBuilder customer = new StringBuilder("");
customer.append(num + "号");
if (list == common) {
customer.append("普通客户");
} else if (list == express) {
customer.append("快速客户");
} else {
customer.append("vip客户");
}
System.out.println(this.name + "开始为" + customer.toString() + "服务---------->");
//根据传递进来的radix让线程睡眠多少秒,表示服务正在进行
int time = 0;
try {
time = r.nextInt(radix) + 3;
Thread.sleep(time * 1000);
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println(this.name + "结束了为" + customer.toString() + "的服务,耗时" + time + "秒<-----------");
return true;
}
/**
* run方法根据本窗口的类型,分情况调用上面的服务方法
*/
@Override
public void run() {
while (true) {
switch (type) {
case COMMON:
serveCustomer(common, 6);
break;
case EXPRESS:
//快速窗口没有接受到快速客户队列的服务请求的时候,可以接受普通客户队列的请求
if (!serveCustomer(express, 2)) {
serveCustomer(common, 4);
}
break;
case VIP:
//vip窗口没有接受到vip客户队列的服务请求的时候,可以接受普通客户队列的请求
if (!serveCustomer(vip, 4)) {
serveCustomer(common, 5);
}
break;
}
}
}
}
复制代码
窗口类型代码:
package cn.itheima.wxn.bankQueue;
public enum WindowType {
COMMON,EXPRESS,VIP;
public String toString(){
switch(this){
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return "VIP";
}
return null;
}
}
作者:
volvoxc
时间:
2014-3-2 13:58
只是判断了在VIP和快速窗口没有对应类型的客户时应该怎么做,而没写有对应的客户时应该怎么做。当有对应类型的客户时,你直接break了。写个if - else看看能不能解决问题。
作者:
qqwwdr
时间:
2014-3-2 14:57
volvoxc 发表于 2014-3-2 13:58
只是判断了在VIP和快速窗口没有对应类型的客户时应该怎么做,而没写有对应的客户时应该怎么做。当有对应类 ...
应该不是这里的问题吧,
break语句只是跳过了switch判断,
没有跳出while循环,而且我在run中是直接调用方法serveCustomer()得到返回值,
在serveCustomer()方法里,我判断 了模拟队列不是空的时候, 直接就执行类啊,
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2