模擬實現銀行業務調度系統邏輯,具體需求如下:
銀行內有6個業務窗口,1 - 4號窗口爲普通窗口,5號窗口爲快速窗口,6號窗口爲VIP窗口。
有三種對應類型的客戶:VIP客戶,普通客戶,快速客戶(辦理如交水電費、電話費之類業務的客戶)。
異步隨機生成各種類型的客戶,生成各類型用戶的概率比例爲:
VIP客戶 :普通客戶 :快速客戶 = 1 :6 :3。
客戶辦理業務所需時間有最大值和最小值,在該範圍內隨機設定每個VIP客戶以及普通客戶辦理業務所需的時間,快速客戶辦理業務所需時間爲最小值(提示:辦理業務的過程可通過線程Sleep的方式模擬)。
各類型客戶在其對應窗口按順序依次辦理業務。
當VIP(6號)窗口和快速業務(5號)窗口沒有客戶等待辦理業務的時候,這兩個窗口可以處理普通客戶的業務,而一旦有對應的客戶等待辦理業務的時候,則優先處理對應客戶的業務。
隨機生成客戶時間間隔以及業務辦理時間最大值和最小值自定,可以設置。
不要求實現GUI,只考慮系統邏輯實現,可通過Log方式展現程序運行結果。
思路:
1.一個客戶其實就是由銀行的取號機生成的一個號碼
2.由於客戶有三類,每類客戶的號碼編制都是完全獨立的,所以本程序一定要產生三個號碼管理器對象,各自管理一類客戶的排隊號碼,這三個號碼管理器對象統一由一個取號機來管理,這個取號機對象在整個程序中只能有一個,所以要將其設計爲單例
3.各種類型的客戶在其對應窗口依次辦理業務,準確的說,應該是窗口依次叫號,當一個窗口叫號時,要向對應的號碼管理器取號
代碼如下:
public class Constants {
// 客戶辦理業務所需時間最小值, 單位爲秒
public static int MIN_SERVICE_TIME = 1;
// 客戶辦理業務所需時間最大值
public static int MAX_SERVICE_TIME = 10;
// 隨機生成普通客戶的比例爲1
public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;
}
public enum CustomerType {
COMMON, EXPRESS, VIP;
public String toString() {
switch (this) {
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return "VIP";
}
return null;
}
}
public class NumberManager {
// 最後一個被取的號碼
private int lastNumber = 1;
// 取完號碼後要排隊,這個集合就用來模仿隊列
private List<Integer> queueNumber = new ArrayList<Integer>();
// 客戶取號時調用次方法,產生新的號碼
public synchronized Integer generateNewNumber() {
// 加入隊列
queueNumber.add(lastNumber);
// 將號碼返回給調用者
return lastNumber++;
}
// 服務窗口叫號時調用這個方法,得到在隊列裏面的第一個號碼
public synchronized Integer fetchServiceNumber() {
if (queueNumber.isEmpty()) {
return null;
}
return queueNumber.remove(0);
}
}
public class NumberMechine {
private NumberManager vipNumberManager = new NumberManager();
private NumberManager commonNumberManager = new NumberManager();
private NumberManager expressNumberManager = new NumberManager();
public NumberManager getVipNumberManager() {
return vipNumberManager;
}
public NumberManager getCommonNumberManager() {
return commonNumberManager;
}
public NumberManager getExpressNumberManager() {
return expressNumberManager;
}
private NumberMechine() {
}
private static NumberMechine instance = new NumberMechine();
// 返回取號機實例
public static NumberMechine getInstance() {
return instance;
}
}
public class ServiceWindow {
// 取號機
public static NumberMechine numberMechine = NumberMechine.getInstance();
// 窗口類型,和客戶類型一致,默認爲普通類型
private CustomerType type = CustomerType.COMMON;
// 窗口編號
private int windowId = 1;
public void setType(CustomerType type) {
this.type = type;
}
public void setWindowId(int windowId) {
this.windowId = windowId;
}
// 使窗口進入可服務狀態,開始叫號並服務
public void start() {
Executors.newSingleThreadExecutor().execute(new Runnable() {
public void run() {
while (true) {
Long serviceTime = (new Random()
.nextInt(Constants.MAX_SERVICE_TIME
- Constants.MIN_SERVICE_TIME + 1) + 1) * 1000l;
switch (type) {
case COMMON:
// 叫號
service(numberMechine.getCommonNumberManager(),
serviceTime, CustomerType.COMMON);
break;
case EXPRESS:
boolean flag = service(
numberMechine.getExpressNumberManager(),
Constants.MIN_SERVICE_TIME * 1000l,
CustomerType.EXPRESS);
// 如果沒有快速客戶,爲普通客戶服務
if (!flag) {
service(numberMechine.getCommonNumberManager(),
serviceTime, CustomerType.COMMON);
}
break;
case VIP:
boolean flag2 = service(
numberMechine.getVipNumberManager(),
serviceTime, CustomerType.VIP);
// 如果沒有VIP客戶,爲普通客戶服務
if (!flag2) {
service(numberMechine.getCommonNumberManager(),
serviceTime, CustomerType.COMMON);
}
break;
}
}
}
});
}
private boolean service(NumberManager numberManager, Long serviceTime,
CustomerType customerType) {
// 叫號
Integer number = numberManager.fetchServiceNumber();
System.out.println(windowId + "號" + type + "窗口開始獲取" + customerType
+ "任務");
// 如果沒有叫到號,休息一秒
if (number == null) {
// 如果叫的號是普通客戶並且沒有叫到,說明銀行現在沒有排隊的客戶,空閒1秒
if (customerType == CustomerType.COMMON) {
System.out.println(windowId + "號" + type + "窗口沒有獲取到"
+ customerType + "任務,正在空閒一秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
System.out.println(windowId + "號" + type + "窗口沒有獲取到" + customerType
+ "任務");
return false;
} else {// 如果叫到了號,就開始爲客戶服務
System.out.println(windowId + "號" + type + "窗口開始爲" + number + "號"
+ customerType + "客戶服務");
// 開始時間
Long biginTime = System.currentTimeMillis();
try {
Thread.sleep(serviceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 本次服務所用的時間
Long costTime = System.currentTimeMillis() - biginTime;
System.out.println(windowId + "號" + type + "窗口爲" + number + "號"
+ customerType + "客戶服務完成,耗時" + costTime / 1000 + "秒");
return true;
}
}
}
public class MainClass {
public static void main(String[] args) {
// 開啓4個普通窗口
for (int i = 1; i <= 4; i++) {
ServiceWindow commonServiceWindow = new ServiceWindow();
commonServiceWindow.setWindowId(i);
commonServiceWindow.start();
}
// 開啓1個快速窗口
ServiceWindow expressServiceWindow = new ServiceWindow();
expressServiceWindow.setType(CustomerType.EXPRESS);
expressServiceWindow.start();
// 開啓1個VIP窗口
ServiceWindow vipServiceWindow = new ServiceWindow();
vipServiceWindow.setType(CustomerType.VIP);
vipServiceWindow.start();
// 製造普通客戶
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
public void run() {
NumberMechine.getInstance().getCommonNumberManager().generateNewNumber();
}
}, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS);
// 製造快速客戶
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
public void run() {
NumberMechine.getInstance().getExpressNumberManager().generateNewNumber();
}
}, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME * 3, TimeUnit.SECONDS);
// 製造vip客戶
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
public void run() {
NumberMechine.getInstance().getVipNumberManager().generateNewNumber();
}
}, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6, TimeUnit.SECONDS);
}
}