银行调度,模拟了实际生活中的银行对客户服务的排队管理系统。
将现实中排队管理,抽象为对象模型。 抽象出了一个号码机,为每个客户生产号码标识,并形成一个先进先出的队列,模拟了现实中的排队。
将对客户的服务,进行抽象,得出是由服务窗口进行叫号,而不是窗口服务员。
这个案例的核心,就是号码管理机器,为每个客户生成一个号码,并排成先进先出队列,模拟了实际生活。然后由 服务窗口,取队列的号,进行服务,模拟了现实中的服务窗口。
1 //常量定义
2 public class Constants {
3 public static int MAX_SERVICE_TIME = 10000; //10秒!
4 public static int MIN_SERVICE_TIME = 1000; //1秒!
5
6 /*每个普通窗口服务一个客户的平均时间为5秒,一共有4个这样的窗口,也就是说银行的所有普通窗口合起来
7 * 平均1.25秒内可以服务完一个普通客户,再加上快速窗口和VIP窗口也可以服务普通客户,所以,
8 * 1秒钟产生一个普通客户比较合理,*/
9 public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;
10 }
11
1 //客户类型
2 public enum CustomerType {
3 COMMON,EXPRESS,VIP;
4 public String toString(){
5 String name = null;
6 switch(this){
7 case COMMON:
8 name = "普通";
9 break;
10 case EXPRESS:
11 name = "快速";
12 break;
13 case VIP:
14 name = name();
15 break;
16 }
17 return name;
18 }
19 }
20
1 //号码产生器
2 public class NumberMachine {
3
4 private NumberMachine(){}
5 private static NumberMachine instance = new NumberMachine();//单例此类
6 public static NumberMachine getInstance(){
7 return instance;
8 }
9
10 private NumberManager commonManager = new NumberManager(); //生产一个普通号
11 private NumberManager expressManager = new NumberManager(); //生产一个快速号
12 private NumberManager vipManager = new NumberManager(); //生产一个vip号
13 public NumberManager getCommonManager() {
14 return commonManager;
15 }
16 public NumberManager getExpressManager() {
17 return expressManager;
18 }
19 public NumberManager getVipManager() {
20 return vipManager;
21 }
22
23 }
1 //取号机,每来一个客户,生成一个号码,插入到ArrayList
2 import java.util.ArrayList;
3 import java.util.List;
4
5 public class NumberManager {
6 private int lastNumber = 0;
7 private List queueNumbers = new ArrayList();
8
9 public synchronized Integer generateNewNumber(){
10 queueNumbers.add(++lastNumber);
11 return lastNumber;
12 }
13
14 public synchronized Integer fetchNumber(){
15 if(queueNumbers.size()>0){
16 return (Integer)queueNumbers.remove(0);
17 }else{
18 return null;
19 }
20 }
21 }
22
1 //服务窗口,进行叫号,根据客户类型,调用相应的服务类型
2 import java.util.Random;
3 import java.util.concurrent.Executors;
4 import java.util.logging.Logger;
5
6 /**
7 * 没有把VIP窗口和快速窗口做成子类,是因为实际业务中的普通窗口可以随时被设置为VIP窗口和快速窗口。
8 * */
9 public class ServiceWindow {
10 private static Logger logger = Logger.getLogger("cn.itcast.bankqueue");
11 private CustomerType type = CustomerType.COMMON;
12 private int number = 1;
13
14 public CustomerType getType() {
15 return type;
16 }
17
18 public void setType(CustomerType type) {
19 this.type = type;
20 }
21
22 public void setNumber(int number){
23 this.number = number;
24 }
25
26 public void start(){
27 Executors.newSingleThreadExecutor().execute(
28 new Runnable(){
29 public void run(){
30 //下面这种写法的运行效率低,最好是把while放在case下面
31 while(true){
32 switch(type){
33 case COMMON:
34 commonService();
35 break;
36 case EXPRESS:
37 expressService();
38 break;
39 case VIP:
40 vipService();
41 break;
42 }
43 }
44 }
45 }
46 );
47 }
48
49 private void commonService(){
50 String windowName = "第" + number + "号" + type + "窗口";
51 System.out.println(windowName + "开始获取普通任务!");
52 Integer serviceNumber = NumberMachine.getInstance().getCommonManager().fetchNumber();
53 if(serviceNumber != null ){
54 System.out.println(windowName + "开始为第" + serviceNumber + "号普通客户服务");
55 int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
56 int serviceTime = new Random().nextInt(maxRandom)+1 + Constants.MIN_SERVICE_TIME;
57
58 try {
59 Thread.sleep(serviceTime);
60 } catch (InterruptedException e) {
61 e.printStackTrace();
62 }
63 System.out.println(windowName + "完成为第" + serviceNumber + "号普通客户服务,总共耗时" + serviceTime/1000 + "秒");
64 }else{
65 System.out.println(windowName + "没有取到普通任务,正在空闲一秒");
66 try {
67 Thread.sleep(1000);
68 } catch (InterruptedException e) {
69 e.printStackTrace();
70 }
71 }
72 }
73
74 private void expressService(){
75 Integer serviceNumber = NumberMachine.getInstance().getExpressManager().fetchNumber();
76 String windowName = "第" + number + "号" + type + "窗口";
77 System.out.println(windowName + "开始获取快速任务!");
78 if(serviceNumber !=null){
79 System.out.println(windowName + "开始为第" + serviceNumber + "号快速客户服务");
80 int serviceTime = Constants.MIN_SERVICE_TIME;
81 try {
82 Thread.sleep(serviceTime);
83 } catch (InterruptedException e) {
84 e.printStackTrace();
85 }
86 System.out.println(windowName + "完成为第" + serviceNumber + "号快速客户服务,总共耗时" + serviceTime/1000 + "秒");
87 }else{
88 System.out.println(windowName + "没有取到快速任务!");
89 commonService();
90 }
91 }
92
93 private void vipService(){
94
95 Integer serviceNumber = NumberMachine.getInstance().getVipManager().fetchNumber();
96 String windowName = "第" + number + "号" + type + "窗口";
97 System.out.println(windowName + "开始获取VIP任务!");
98 if(serviceNumber !=null){
99 System.out.println(windowName + "开始为第" + serviceNumber + "号VIP客户服务");
100 int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
101 int serviceTime = new Random().nextInt(maxRandom)+1 + Constants.MIN_SERVICE_TIME;
102 try {
103 Thread.sleep(serviceTime);
104 } catch (InterruptedException e) {
105 e.printStackTrace();
106 }
107 System.out.println(windowName + "完成为第" + serviceNumber + "号VIP客户服务,总共耗时" + serviceTime/1000 + "秒");
108 }else{
109 System.out.println(windowName + "没有取到VIP任务!");
110 commonService();
111 }
112 }
113 }
114
1 //主类,生成服务窗口,进行叫号,根据叫号时间间隔,达到1:6:3 的客户比例
2 import java.util.concurrent.Executors;
3 import java.util.concurrent.TimeUnit;
4 import java.util.logging.Logger;
5
6 public class MainClass {
7
8 private static Logger logger = Logger.getLogger("cn.itcast.bankqueue");
9
10
11 public static void main(String[] args) {
12 //产生4个普通窗口
13 for(int i=1;i<5;i++){
14 ServiceWindow window = new ServiceWindow();
15 window.setNumber(i);
16 window.start();
17 }
18
19 //产生1个快速窗口
20 ServiceWindow expressWindow = new ServiceWindow();
21 expressWindow.setType(CustomerType.EXPRESS);
22 expressWindow.start();
23
24 //产生1个VIP窗口
25 ServiceWindow vipWindow = new ServiceWindow();
26 vipWindow.setType(CustomerType.VIP);
27 vipWindow.start();
28
29 //普通客户拿号
30 Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
31 new Runnable(){
32 public void run(){
33 Integer serviceNumber = NumberMachine.getInstance().getCommonManager().generateNewNumber();
34 /**
35 * 采用logger方式,无法看到直观的运行效果,因为logger.log方法内部并不是直接把内容打印出出来,
36 * 而是交给内部的一个线程去处理,所以,打印出来的结果在时间顺序上看起来很混乱。
37 */
38 //logger.info("第" + serviceNumber + "号普通客户正在等待服务!");
39 System.out.println("第" + serviceNumber + "号普通客户正在等待服务!");
40 }
41 },
42 0,
43 Constants.COMMON_CUSTOMER_INTERVAL_TIME,
44 TimeUnit.SECONDS);
45
46 //快速客户拿号
47 Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
48 new Runnable(){
49 public void run(){
50 Integer serviceNumber = NumberMachine.getInstance().getExpressManager().generateNewNumber();
51 System.out.println("第" + serviceNumber + "号快速客户正在等待服务!");
52 }
53 },
54 0,
55 Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2,
56 TimeUnit.SECONDS);
57
58 //VIP客户拿号
59 Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
60 new Runnable(){
61 public void run(){
62 Integer serviceNumber = NumberMachine.getInstance().getVipManager().generateNewNumber();
63 System.out.println("第" + serviceNumber + "号VIP客户正在等待服务!");
64 }
65 },
66 0,
67 Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6,
68 TimeUnit.SECONDS);
69 }