黑马程序员-银行业务调度

来源:互联网 发布:淘宝女装文案模板 编辑:程序博客网 时间:2024/05/23 12:57

---------------------android培训、java培训、期待与您交流! -------------------------

银行业务调度系统需求:

  1. 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
  2. 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)
  3. 异步随机生成各种类型的客户,生成各类型用户的概率比例为: VIP客户 :普通客户 :快速客户 = 1 :6 :3。
  4. 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小 值(提示:办理业务的过程可通过线程Sleep的方式模拟)
  5. 各类型客户在其对应窗口按顺序依次办理业务。
  6. 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
  7. 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置
  8. 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。

分析需求,确定生产者与消费者关系:

生产者:
异步随机生成各种类型的客户,生成各类型用户的概率比例为:VIP客户 :普通客户 :快速客户 = 1 :6 :3
该功能由NumberMachine完成,即银行的叫号机

消费者:
银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口

生产-消费规则:
生产三种类型用户:VIP, 普通, 快速
生产时间间隔可配置。
消费者消费耗时随机,并有范围限制
消费者消费时,当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。可考虑模板模式

生产者类型限定:

package com.uc.bank;public enum CustomerType {VIP, EXPRESS, COMM}

生产者与消费者时间常数:

package com.uc.bank;/** * 用来定义系统中用到到常量 * @author UC */public final class Constants {/** * 业务办理时间最大值10s */public static int MAX_SERVICE_TIME = 10000; //10秒!/** * 业务办理时间最小值1s */public static int MIN_SERVICE_TIME = 1000; //1秒!/** * 每个普通窗口服务一个客户的平均时间为5秒,一共有4个这样的窗口,也就是说银行的所有普通窗口合起来 * 平均1.25秒内可以服务完一个普通客户,再加上快速窗口和VIP窗口也可以服务普通客户,所以, * 1秒钟产生一个普通客户比较合理 * VIP客户 :普通客户 :快速客户  =  1 :6 :3 */public static int VIP_CUSTOMER_INTERVAL_TIME = 6;public static int COMMON_CUSTOMER_INTERVAL_TIME = VIP_CUSTOMER_INTERVAL_TIME / 6;public static int EXPRESS_CUSTOMER_INTERVAL_TIME = VIP_CUSTOMER_INTERVAL_TIME / 3;}

生产者功能模拟,实现银行叫号机的功能

package com.uc.bank;import java.util.ArrayList;import java.util.List;/** * 管理客户队列的生成 * @author UC * */public final class NumberManager {public NumberManager() {}public NumberManager(CustomerType custType) {this.managerCustomerType = custType;}/** * 控制叫号机生成号码, 模拟银行客户叫号的过程 * @return 返回最后一个用户的号码加1 */public synchronized Integer generateNumber() {//System.out.println("Add " + this.managerCustomerType + " " + lastNumber);list.add(lastNumber++);return lastNumber;}/** * 从队列中取号,模拟银行业务人员呼叫客户的过程 * @return 将要办理业务的客户号码 */public synchronized Integer fetchNumber() {if (!list.isEmpty()) {return list.remove(0);}return null;}private List<integer> list = new ArrayList<>();private Integer lastNumber = 1;private CustomerType managerCustomerType = null;}</integer>

生产者,模拟用户叫号功能,使用到单例模式

package com.uc.bank;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;/** * 控制客户队列的生成 * 要求:VIP客户 :普通客户 :快速客户  =  1 :6 :3 *      随机生成客户时间间隔 * @author UC * */public final class NumberMachine {/** *  * @return 返回叫号机实例 */public static NumberMachine getInstance() {return machine;}/** *  * @return 返回普通用户队列管理对象 */public NumberManager getCommManager() {return commManager;}/** *  * @return 返回快速用户队列管理对象 */public NumberManager getExpressManager() {return expressManager;}/** *  * @return 返回VIP客户队列管理对象 */public NumberManager getVIPManager() {return vipManager;}/** * 控制叫号机开始工作,即开始生成用户队列 */public void startWork() {//VIP队列生产者Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubvipManager.generateNumber();}}, 0, Constants.VIP_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS);//快速客户生产者Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubexpressManager.generateNumber();}}, 0, Constants.EXPRESS_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS);//普通客户生产者Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubcommManager.generateNumber();}}, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS);}private final NumberManager commManager = new NumberManager(CustomerType.COMM);private final NumberManager expressManager = new NumberManager(CustomerType.EXPRESS);private final NumberManager vipManager = new NumberManager(CustomerType.VIP);private static final NumberMachine machine = new NumberMachine();}

银行窗口服务规则模拟,考虑到固定的流程,使用模板模式

package com.uc.bank;import java.util.concurrent.Executors;/** * 业务规则: *当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务, * 而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。 *  * 因为是固定的流程, 可以做成模板 */public abstract class AbstractService {/** * 服务ID */private Integer serviceID;/** * 运行标志 */private boolean runFlag;public Integer getServiceID() {return serviceID;}public void setServiceID(Integer serviceID) {this.serviceID = serviceID;}public abstract void secondAction();public abstract void firstAction();protected abstract Integer callNumber();public void startService() {if (runFlag) {return;//已经开始运行,则不允许再次调用Service服务}runFlag = true;Executors.newSingleThreadExecutor().execute(new Runnable() {@Overridepublic void run() {while (runFlag) {serviceID = callNumber();if (null != serviceID) {firstAction();} else {secondAction();}}}});}public void stopService() {runFlag = false;}}

模拟银行窗口的具体服务。

package com.uc.bank;/** * 消费者-生产者规则: * 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间 *             快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟) *  * 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务, * 而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。 *  * 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。 */public class CommWindow extends AbstractService {/** * 服务窗口ID */private Integer windowID;/** * 服务用户类型 */private CustomerType customerType;public CommWindow(Integer windowID, CustomerType customerType) {super();this.windowID = windowID;this.customerType = customerType;}public CommWindow() {super();}public Integer getWindowID() {return windowID;}public void setWindowID(Integer windowID) {this.windowID = windowID;}public CustomerType getCustomerType() {return customerType;}public void setCustomerType(CustomerType customerType) {this.customerType = customerType;}private int getServiceTime() {//快速客户办理业务所需时间为最小值if (customerType == CustomerType.EXPRESS) {return Constants.MIN_SERVICE_TIME;}//客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间int rangeTime = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;int serviceTime = (int)(Math.random() * rangeTime + Constants.MIN_SERVICE_TIME);return serviceTime;}//当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,//而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。@Overridepublic void secondAction() {if (getCustomerType() == CustomerType.COMM) {return;}CustomerType oldType = getCustomerType();try {setCustomerType(CustomerType.COMM);Integer serviceId = callNumber();if (null != serviceId) {setServiceID(serviceId);firstAction();} else {System.out.println("Window " + getWindowID() + " there are not comm user in queue");}} finally {setCustomerType(oldType);}}@Overridepublic void firstAction() {System.out.println("Window " + getWindowID() + " start to service " +getCustomerType() + " customer " + getServiceID());long t = System.currentTimeMillis();//服务耗时try {Thread.sleep(getServiceTime());} catch (InterruptedException e) {e.printStackTrace();}long spendTime = System.currentTimeMillis() - t;System.out.println("Window " + getWindowID() + " done service for " + getCustomerType() + " customer " + getServiceID() + " and spend " + spendTime + " ms");}@Overrideprotected Integer callNumber() {Integer no = null;NumberMachine machine = NumberMachine.getInstance();switch(getCustomerType()) {case COMM:no = machine.getCommManager().fetchNumber();break;case EXPRESS:no = machine.getExpressManager().fetchNumber();break;case VIP:no = machine.getVIPManager().fetchNumber();break;default:break;}return no;}}

模拟银行的职能, 拥有叫号机与窗口,并管理它们。

package com.uc.bank;import java.util.ArrayList;import java.util.List;public class Bank {public Bank() {listWindows = new ArrayList<>();machine = null;}public Bank(NumberMachine machine, List<commwindow> list) {this.machine = machine;this.listWindows = list;}public void addWindow(CommWindow window) {listWindows.add(window);}public void setMachine(NumberMachine machine) {this.machine = machine;}public void startWork() {if (null == machine) {System.out.println("叫号机没有设置");return;}if (listWindows.size() == 0) {System.out.println("窗口还没有添加");return;}this.machine.startWork();try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}for (CommWindow win : listWindows) {win.startService();}}private NumberMachine machine;private List<commwindow> listWindows;}</commwindow></commwindow>

主类,负责初始化资源,启动应用。

package com.uc.bank;/* * 用多线程模拟生产者与消费者,要求有多个生产者和多个消费者。生产者生产资源,消费者消耗资源。 *  * 生产者: * 异步随机生成各种类型的客户,生成各类型用户的概率比例为: *      VIP客户 :普通客户 :快速客户  =  1 :6 :3 * 消费者: * 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口 *  * 消费者-生产者规则: * 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间 * 快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟) * 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务, * 而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。 * 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。 */public class MainClass {public static void main(String[] args) {Bank bank = new Bank();//生产者-单例NumberMachine machine = NumberMachine.getInstance();bank.setMachine(machine);//1-4 号窗口,服务普通用户for (int i = 1; i <= 4; i++) {bank.addWindow(new CommWindow(i, CustomerType.COMM));}//5号, 快速窗口bank.addWindow(new CommWindow(5, CustomerType.EXPRESS));//6号, VIP窗口bank.addWindow(new CommWindow(6, CustomerType.VIP));bank.startWork();}}

---------------------android培训、java培训、期待与您交流! -------------------------

0 0
原创粉丝点击