多线程模拟银行业务调度系统
一、项目业务逻辑分析
项目需求:模拟实现银行业务调度系统逻辑,要求如下:
银行内有6个业务窗口,1-4号为普通窗口,5号为快速窗口,6号为VIP窗口。
对应3中类型的客户:普通客户,VIP客户,快速客户(办理如交水电费,电话费之类的业务)
异步随机生成各种各类型的客户,比例VIP:普通客户:快速客户:1:6:3。
客户办理业务所需时间有最大值和最小值,普通客户和VIP客户办理业务所需时间再两者之间,快速客户取最小值。
当VIP窗口和快速窗口没有客户等待办理业务时,这两个窗口可以处理普通客户的业务。
该题目的业务逻辑和交通灯管理系统有很多相似之处,都是基于多线程并发执行的业务逻辑,至少需要2个线程,业务窗口线程:负责即时检测有没有对应的客户在排队,VIP窗口和快速窗口在没有对应客户排队的情况下,可以处理普通客户的业务。生成客户线程:每个一定的时间就产生一个不同类型的客户。在现实的银行营业厅中都有一个排好机,选择业务类型就会打印出一个排队号码,这里我们也模拟设计一个排号机,负责客户排队。
二、系统详细设计
根据业务需求分析,设计这样几个对象:服务窗口对象,客户对象,排号机对象。下面具体分析每个对象所以属性和方法。
服务窗口对象:应该有窗口类型和窗口编号两个属性。提供3个方法,用于检测3种类型的客户是否又在排队的。
客户对象:这里系统主要是银行的业务逻辑,客户不需要具体化,用一个数字或字符串表示就行了。但是需要一个客户类型对象来表示不同的客户,这里用枚举类型实现。
排号机对象:对办理业务的客户排号的前提是先有客户,所以排号机兼负产生模拟客户的人物,产生一个客户也就是有一个客户进入对应类型的排队排列。
主要类图如下:
具体实现和业务逻辑分析略有不同,但整体设计是相同的。
三、具体实现
NumberManager.java
public class NumberManager {
private int lastNumber = 0;
//客戶排队队列
private List<Integer> queueNumbers = new ArrayList<Integer>();
//随机产生模拟客户
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.java
public class ServiceWindow {
// 根据客户类型获取下一个客户
private CustomerType type = null;
// 服务窗口编号
private int windowId = 1;
public ServiceWindow(CustomerType type, int windowId) {
super();
this.type = type;
this.windowId = windowId;
}
public void start() {
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
do{
switch (type) {
case COMMON:
commonService();
break;
case VIP:
expressService();
break;
case EXPRESS:
vipService();
break;
default:
break;
}
}while(true);
}
});
}
private void commonService() {
String windowName = windowId + "号普通窗口";
// 尝试从客户排队队列中获取下一个客户
System.out.println(windowName + " 正在获取任务。。。");
Integer serviceNum = NumberMachine.getInstance().getCommonManager()
.fetchNumber();
if (serviceNum != null) {
// 用sleep模拟客户服务时间
System.out.println(windowName + "开始为" + serviceNum + "号普通客户服务");
int max_Random = Constants.MAX_SERVICE_TIME
- Constants.MIN_SERVICE_TIME;
long serviceTime = new Random().nextInt(max_Random) + 1+Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(serviceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(windowName + "为 " + serviceNum
+ " 号普通客户服务完成,用时:" + serviceTime / 1000 + " 秒");
} else {
System.out.println(windowName + " 没有获取到客户,等待中。。。");
try {// 等待1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CustomerType.java
public enum CustomerType {
VIP,EXPRESS,COMMON;
public String toString(){
switch (this) {
case VIP:
return "VIP";
case EXPRESS:
return "快速";
case COMMON:
return "普通";
}
return null;
}
}
NumberMachine.java
public class NumberMachine {
private static NumberMachine instance = new NumberMachine();
//普通客戶排号机
private NumberManager commonManager = new NumberManager();
//快速客戶排号机
private NumberManager expressManager = new NumberManager();
//VIP客戶排号机
private NumberManager vipManager = new NumberManager();
//单例模式创建一个号码管理器
private NumberMachine(){}
public static NumberMachine getInstance(){
return instance;
}
public NumberManager getCommonManager() {
return commonManager;
}
public NumberManager getExpressManager() {
return expressManager;
}
public NumberManager getVipManager() {
return vipManager;
}
}