银行业务调度系统

银行业务调度系统

 

 

1.   模拟实现银行业务调度系统逻辑

     具体需求如下:
    银行内有6个业务窗口,1-4为普通窗口,5为快速窗口,6为VIP窗口。
    有三种类型客户:VIP客户,快速客户(交水电费类业务、电话费之类业务的客户),普通客户。
    异步随机生成各种类型的客户,生成概率比例为:VIP客户:快速客户:普通客户 = 1:3:6.
    客户办理业务所需时间有最大值和最小值,在该范围内随机设定,每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需,时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
    各类型客户在其对应窗口按照顺序办理业务。
    VIP和快速窗口无办理业务时刻受理普通客户,若有应该优先处理对应客户。

2.学习收获:
第一:当两个不同的线程访问了相同的数据,
如代码中:

public class NumberManager {
      private int lastNumber = 0;
      private List queueNumbers = new ArrayList();
      
      public synchronized Integer generateNewNumber(){
            queueNumbers.add(++lastNumber);
            return lastNumber;
      }
      
      public synchronized Integer fetchNumber(){
            if(queueNumbers.size()>0){
                  return (Integer)queueNumbers.remove(0);
            }else{
                  return null;
            }
      }
}
 

这两个方法generateNewNumber()和fetchNumber()处于不同的线程,却处理相同的数据,要实现互斥。所以得加上synchronized。

第二:
NumberMachine类
定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,定义三个对应的方法来返回这三个NumberManager对象。
将NumberMachine类设计成单例。

单例模式:

     

private NumberMachine(){}
      private static NumberMachine instance = new NumberMachine();
      public static NumberMachine getInstance(){
            return instance;
      }
 

      
第三:if else 为什么比switch效率低
首先要看一个问题,if 语句适用范围比较广,只要是 boolean 表达式都可以用 if 判断;而 switch 只能对基本类型进行数值比较。两者的可比性就仅限在两个基本类型比较的范围内。
说到基本类型的数值比较,那当然要有两个数。然后重点来了——
if 语句每一句都是独立的,看下面的语句:
if (a == 1) ...
else if (a == 2) ...
这样 a 要被读入寄存器两次,1 和 2 分别被读入寄存器一次。于是你是否发现其实 a 读两次是有点多余的,在你全部比较完之前只需要一次读入寄存器就行了,其余都是额外开销。但是 if 语句必须每次都把里面的两个数从内存拿出来读到寄存器,它不知道你其实比较的是同一个 a。
于是 switch case 就出来了,把上面的改成 switch case 版本:
switch (a) {
        case 0:
                break;
        case 1:
}
因为特定的规则,他一开始就知道你要比 a,于是 a 一次性读取,相比 if 节约了很多开销。

最终生成的Uml图:


NumberMachine类
public class NumberMachine {
      
      private NumberMachine(){}
      private static NumberMachine instance = new NumberMachine();
      public static NumberMachine getInstance(){
            return instance;
      }
      
      private NumberManager commonManager = new NumberManager();
      private NumberManager expressManager = new NumberManager();
      private NumberManager vipManager = new NumberManager();
      public NumberManager getCommonManager() {
            return commonManager;
      }
      public NumberManager getExpressManager() {
            return expressManager;
      }
      public NumberManager getVipManager() {
            return vipManager;
      }
      
}
NumberManager类
public class NumberManager {
      private int lastNumber = 0;
      private List queueNumbers = new ArrayList();

      public synchronized Integer generateNewNumber() {
            queueNumbers.add(++lastNumber);
            return lastNumber;
      }

      public synchronized Integer fetchNumber() {
            if (queueNumbers.size() > 0) {
                  return (Integer) queueNumbers.remove(0);
            } else {
                  return null;
            }
      }
}

ServiceWindow类
/**
 * 没有把VIP窗口和快速窗口做成子类,是因为实际业务中的普通窗口可以随时被设置为VIP窗口和快速窗口。
 * */
public class ServiceWindow {
      private static Logger logger = Logger.getLogger("cn.itcast.bankqueue");
      private CustomerType type = CustomerType.COMMON;
      private int number = 1;

      public CustomerType getType() {
            return type;
      }

      public void setType(CustomerType type) {
            this.type = type;
      }

      public void setNumber(int number) {
            this.number = number;
      }

      public void start() {
            Executors.newSingleThreadExecutor().execute(new Runnable() {
                  public void run() {
                        // 下面这种写法的运行效率低,最好是把while放在case下面
                        while (true) {
                              switch (type) {
                              case COMMON:
                                    commonService();
                                    break;
                              case EXPRESS:
                                    expressService();
                                    break;
                              case VIP:
                                    vipService();
                                    break;
                              }
                        }
                  }
            });
      }

      private void commonService() {
            String windowName = "第" + number + "号" + type + "窗口";
            System.out.println(windowName + "开始获取普通任务!");
            Integer serviceNumber = NumberMachine.getInstance().getCommonManager()
                        .fetchNumber();
            if (serviceNumber != null) {
                  System.out.println(windowName + "开始为第" + serviceNumber + "号普通客户服务");
                  int maxRandom = Constants.MAX_SERVICE_TIME
                              - Constants.MIN_SERVICE_TIME;
                  int serviceTime = new Random().nextInt(maxRandom) + 1
                              + Constants.MIN_SERVICE_TIME;

                  try {
                        Thread.sleep(serviceTime);
                  } catch (InterruptedException e) {
                        e.printStackTrace();
                  }
                  System.out.println(windowName + "完成为第" + serviceNumber
                              + "号普通客户服务,总共耗时" + serviceTime / 1000 + "秒");
            } else {
                  System.out.println(windowName + "没有取到普通任务,正在空闲一秒");
                  try {
                        Thread.sleep(1000);
                  } catch (InterruptedException e) {
                        e.printStackTrace();
                  }
            }
      }

      private void expressService() {
            Integer serviceNumber = NumberMachine.getInstance().getExpressManager()
                        .fetchNumber();
            String windowName = "第" + number + "号" + type + "窗口";
            System.out.println(windowName + "开始获取快速任务!");
            if (serviceNumber != null) {
                  System.out.println(windowName + "开始为第" + serviceNumber + "号快速客户服务");
                  int serviceTime = Constants.MIN_SERVICE_TIME;
                  try {
                        Thread.sleep(serviceTime);
                  } catch (InterruptedException e) {
                        e.printStackTrace();
                  }
                  System.out.println(windowName + "完成为第" + serviceNumber
                              + "号快速客户服务,总共耗时" + serviceTime / 1000 + "秒");
            } else {
                  System.out.println(windowName + "没有取到快速任务!");
                  commonService();
            }
      }

      private void vipService() {

            Integer serviceNumber = NumberMachine.getInstance().getVipManager()
                        .fetchNumber();
            String windowName = "第" + number + "号" + type + "窗口";
            System.out.println(windowName + "开始获取VIP任务!");
            if (serviceNumber != null) {
                  System.out
                              .println(windowName + "开始为第" + serviceNumber + "号VIP客户服务");
                  int maxRandom = Constants.MAX_SERVICE_TIME
                              - Constants.MIN_SERVICE_TIME;
                  int serviceTime = new Random().nextInt(maxRandom) + 1
                              + Constants.MIN_SERVICE_TIME;
                  try {
                        Thread.sleep(serviceTime);
                  } catch (InterruptedException e) {
                        e.printStackTrace();
                  }
                  System.out.println(windowName + "完成为第" + serviceNumber
                              + "号VIP客户服务,总共耗时" + serviceTime / 1000 + "秒");
            } else {
                  System.out.println(windowName + "没有取到VIP任务!");
                  commonService();
            }
      }
}
public class Constants {
      public static int MAX_SERVICE_TIME = 10000; //10秒!
      public static int MIN_SERVICE_TIME = 1000; //1秒!
      
      /*每个普通窗口服务一个客户的平均时间为5秒,一共有4个这样的窗口,也就是说银行的所有普通窗口合起来
       * 平均1.25秒内可以服务完一个普通客户,再加上快速窗口和VIP窗口也可以服务普通客户,所以,
       * 1秒钟产生一个普通客户比较合理,*/      
      public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;  
}
public enum CustomerType {
      COMMON,EXPRESS,VIP;
      public String toString(){
            String name = null;
            switch(this){
            case COMMON:
                  name = "普通";
                  break;
            case EXPRESS:
                  name = "快速";
                  break;
            case VIP:
                  name = name();
                  break;
            }
            return name;
      }
}


程序运行:
public class MainClass {
      
      private static Logger logger = Logger.getLogger("cn.itcast.bankqueue");
      

      public static void main(String[] args) {
            //产生4个普通窗口
            for(int i=1;i<5;i++){
                  ServiceWindow window =  new ServiceWindow();
                  window.setNumber(i);
                  window.start();
            }
      
            //产生1个快速窗口
            ServiceWindow expressWindow =  new ServiceWindow();
            expressWindow.setType(CustomerType.EXPRESS);
            expressWindow.start();
            
            //产生1个VIP窗口        
            ServiceWindow vipWindow =  new ServiceWindow();
            vipWindow.setType(CustomerType.VIP);
            vipWindow.start();            
            
            //普通客户拿号
            Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
                        new Runnable(){
                              public void run(){
                                    Integer serviceNumber = NumberMachine.getInstance().getCommonManager().generateNewNumber();
                                    /**
                                     * 采用logger方式,无法看到直观的运行效果,因为logger.log方法内部并不是直接把内容打印出出来,
                                     * 而是交给内部的一个线程去处理,所以,打印出来的结果在时间顺序上看起来很混乱。
                                     */
                                    //logger.info("第" + serviceNumber + "号普通客户正在等待服务!");
                                    System.out.println("第" + serviceNumber + "号普通客户正在等待服务!");                                  
                              }
                        },
                        0,
                        Constants.COMMON_CUSTOMER_INTERVAL_TIME,
                        TimeUnit.SECONDS);
            
            //快速客户拿号
            Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
                        new Runnable(){
                              public void run(){
                                    Integer serviceNumber = NumberMachine.getInstance().getExpressManager().generateNewNumber();
                                    System.out.println("第" + serviceNumber + "号快速客户正在等待服务!");
                              }
                        },
                        0,
                        Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2,
                        TimeUnit.SECONDS);
            
            //VIP客户拿号
            Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
                        new Runnable(){
                              public void run(){
                                    Integer serviceNumber = NumberMachine.getInstance().getVipManager().generateNewNumber();
                                    System.out.println("第" + serviceNumber + "号VIP客户正在等待服务!");
                              }
                        },
                        0,
                        Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6,
                        TimeUnit.SECONDS);
      }

}
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值