我用 等待唤醒机制 重写 了 银行业务调度系统,
有时候会出现这种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;
}
}
|