A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© qqwwdr 中级黑马   /  2014-3-2 13:40  /  876 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

我用 等待唤醒机制 重写 了 银行业务调度系统,
有时候会出现这种bug:
           当VIP窗口或者是快速窗口 对应的VIP客户或者是快速业务客户还有的时候,VIP窗口或者是快速窗口跑去处理普通客户去了,
    自己分析了一晚上也没找到原因,求助高手解惑
代码如下:
主类:
  1. package cn.itheima.wxn.bankQueue;

  2. import java.util.*;

  3. public class BankQueue {
  4.         //三个队列模拟三种客户排队
  5.         public static List<Integer> common = new ArrayList<Integer>();
  6.         public static List<Integer> express = new ArrayList<Integer>();
  7.         public static List<Integer> vip = new ArrayList<Integer>();

  8.         public static void main(String[] args) {
  9.                 //将三个队列转换成线程安全
  10.                 common = Collections.synchronizedList(common);
  11.                 express = Collections.synchronizedList(express);
  12.                 vip = Collections.synchronizedList(vip);

  13.                 //开启为三个队列加入客户的线程
  14.                 new Thread(new CustomerGenerative(common, express, vip)).start();
  15.                 //开启为4个普通窗口的线程
  16.                 for (int i = 1; i < 5; i++) {
  17.                         new Thread(new WindowService(common, express, vip,WindowType.COMMON, i)).start();
  18.                 }
  19.                 //开启快速窗口的线程
  20.                 new Thread(new WindowService(common, express, vip, WindowType.EXPRESS,5)).start();
  21.                 //开启vip窗口的线程
  22.                 new Thread(new WindowService(common, express, vip, WindowType.VIP, 6)).start();
  23.         }
  24. }
复制代码

客户编码产生器:
  1. package cn.itheima.wxn.bankQueue;

  2. import java.util.List;
  3. import java.util.Random;

  4. //产生客户,按6:3:1的几率产生客户
  5. class CustomerGenerative implements Runnable {
  6.         private List<Integer> common;
  7.         private List<Integer> express;
  8.         private List<Integer> vip;

  9.         //构造方法,接收3个模拟队列的集合
  10.         CustomerGenerative(List<Integer> list1, List<Integer> list2,
  11.                         List<Integer> list3) {
  12.                 this.common = list1;
  13.                 this.express = list2;
  14.                 this.vip = list3;
  15.         }
  16.        
  17.         @Override
  18.         public void run() {
  19.                 int commonCount = 0;        //统计总的普通客户的人数
  20.                 int expressCount = 0;        //统计中的快速客户的人数
  21.                 int vipCount = 0;        //统计总的vip客户的人数
  22.                 Integer num = 0;                //递增的索引,可以表示总的客户的人数
  23.                 Random r = new Random();
  24.                 while (true) {
  25.                         //每当有10的倍数个客户进入的时候,输出统计信息
  26.                         if(num%10 == 0){
  27.                                 System.out.println("=====查看排队用户信息=======");
  28.                                 System.out.println(this.common + "全部的普通客户有:" + commonCount + "人");
  29.                                 System.out.println( this.express+ "全部的快速客户有:" + expressCount + "人");
  30.                                 System.out.println( this.vip+ "全部的VIP客户有:" + vipCount + "人");                               
  31.                                 System.out.println("=======================");
  32.                         }
  33.                         num++;
  34.                         //进程睡眠2秒
  35.                         try {
  36.                                 Thread.sleep(r.nextInt(2000));
  37.                         } catch (Exception ex) {
  38.                                 ex.printStackTrace();
  39.                         }
  40.                         //flag用于判断是添加那种类型的客户
  41.                         int flag = r.nextInt(10);        //取0~10之间的随机数,随机数是0~5,是普通客户;6~8是快速客户;9是vip客户
  42.                         if (flag < 6) {
  43.                                 common.add(num);
  44.                                 System.out.println("======>" +num + "号普通客户等待");
  45.                                 commonCount++;
  46.                                 synchronized (common) {
  47.                                         this.common.notifyAll();
  48.                                 }
  49.                         } else if (flag >= 6 && flag < 9) {
  50.                                 express.add(num);
  51.                                 System.out.println("======>" +num + "号快速客户等待");
  52.                                 expressCount++;
  53.                                 synchronized (express) {
  54.                                         this.express.notifyAll();
  55.                                 }
  56.                         } else {
  57.                                 vip.add(num);
  58.                                 System.out.println("======>" + num + "号VIP客户等待");
  59.                                 vipCount++;
  60.                                 synchronized (vip) {
  61.                                         this.vip.notifyAll();
  62.                                 }
  63.                         }
  64.                 }
  65.         }
  66. }
复制代码

窗口类代码:
  1. package cn.itheima.wxn.bankQueue;

  2. import java.util.List;
  3. import java.util.Random;

  4. class WindowService implements Runnable {
  5.         private List<Integer> common;
  6.         private List<Integer> express;
  7.         private List<Integer> vip;
  8.         private String name;
  9.         private WindowType type;
  10.         //无参构造方法
  11.         WindowService() {}
  12.         //构造方法
  13.         WindowService(List<Integer> common, List<Integer> express,
  14.                         List<Integer> vip, WindowType type, int count) {
  15.                 //接收三个模拟队列的集合
  16.                 this.common = common;
  17.                 this.express = express;
  18.                 this.vip = vip;
  19.                 //指定本窗口的类型
  20.                 this.type = type;
  21.                 //指定窗口的名称
  22.                 this.name = count + "号" + this.type + "窗口";
  23.         }

  24.         /**
  25.          * @see 窗口的服务方法
  26.          *@param list:方法接收一个模拟队列的集合,
  27.          *@param radix: 服务的时间等级, 这个等级没有限制,自己微调,表示服务时间的长短
  28.                 @return false,表示没有客户,返回true表示已经服务完客户
  29.         */
  30.         public boolean serveCustomer(List<Integer> list, int radix) {
  31.                 Random r = new Random();       
  32.                 Integer num = null;        //接收从集合中取出的客户的编号
  33.                 //同步代码块,从集合中取元素的功能,
  34.                 synchronized (list) {
  35.                         //如果集合中没有元素的情况下,窗口要么等待,要么接收其他客户队列的服务请求
  36.                         while (list == null || list.isEmpty() || (num = list.remove(0)) == null) {
  37.                                 //如果本窗口不是普通窗口并且客户队列不是普通队列,返回false
  38.                                 if (!this.type.equals(WindowType.COMMON) && list != this.common){
  39.                                         System.out.println("\t~!@#$%^&**()" + this.name + "没能获取相应客户");
  40.                                         return false;
  41.                                 }
  42.                                 //窗口等待
  43.                                 try {
  44.                                         System.out.println("\t[" + this.name + "等待客户******");
  45.                                         list.wait();
  46.                                 } catch (InterruptedException e) {
  47.                                         e.printStackTrace();
  48.                                 }
  49.                         }
  50.                 }
  51.                 //根据取出的编号得到客户的名称
  52.                 StringBuilder customer = new StringBuilder("");
  53.                 customer.append(num + "号");
  54.                 if (list == common) {
  55.                         customer.append("普通客户");
  56.                 } else if (list == express) {
  57.                         customer.append("快速客户");
  58.                 } else {
  59.                         customer.append("vip客户");
  60.                 }
  61.                 System.out.println(this.name + "开始为" + customer.toString()        + "服务---------->");
  62.                 //根据传递进来的radix让线程睡眠多少秒,表示服务正在进行
  63.                 int time = 0;
  64.                 try {
  65.                         time = r.nextInt(radix) + 3;
  66.                         Thread.sleep(time * 1000);
  67.                 } catch (Exception ex) {
  68.                         ex.printStackTrace();
  69.                 }
  70.                 System.out.println(this.name + "结束了为" + customer.toString() + "的服务,耗时" + time + "秒<-----------");
  71.                 return true;
  72.         }

  73.         /**
  74.          * run方法根据本窗口的类型,分情况调用上面的服务方法
  75.          */
  76.         @Override
  77.         public void run() {
  78.                 while (true) {
  79.                         switch (type) {
  80.                         case COMMON:
  81.                                 serveCustomer(common, 6);
  82.                                 break;
  83.                         case EXPRESS:
  84.                                 //快速窗口没有接受到快速客户队列的服务请求的时候,可以接受普通客户队列的请求
  85.                                 if (!serveCustomer(express, 2)) {
  86.                                         serveCustomer(common, 4);
  87.                                 }
  88.                                 break;
  89.                         case VIP:
  90.                                 //vip窗口没有接受到vip客户队列的服务请求的时候,可以接受普通客户队列的请求
  91.                                 if (!serveCustomer(vip, 4)) {
  92.                                         serveCustomer(common, 5);
  93.                                 }
  94.                                 break;
  95.                         }
  96.                 }
  97.         }
  98. }
复制代码

窗口类型代码:
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;
        }
}


评分

参与人数 1技术分 +1 收起 理由
何伟超 + 1

查看全部评分

2 个回复

倒序浏览
只是判断了在VIP和快速窗口没有对应类型的客户时应该怎么做,而没写有对应的客户时应该怎么做。当有对应类型的客户时,你直接break了。写个if - else看看能不能解决问题。
回复 使用道具 举报
volvoxc 发表于 2014-3-2 13:58
只是判断了在VIP和快速窗口没有对应类型的客户时应该怎么做,而没写有对应的客户时应该怎么做。当有对应类 ...

应该不是这里的问题吧,
break语句只是跳过了switch判断,
没有跳出while循环,而且我在run中是直接调用方法serveCustomer()得到返回值,
在serveCustomer()方法里,我判断 了模拟队列不是空的时候, 直接就执行类啊,
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马