JavaSE(13):银行业务调度系统,javase调度系统
JavaSE(13):银行业务调度系统,javase调度系统
7K面试之银行业务调度系统
1、业务分析:
模拟整个银行大厅的工作,需要在大脑中构建银行大厅的场景。主要是两个过程。1)、陆续随机进入三种类型(普通、快速服务、vip)的客户,他们去取票排队,取号机分类将他们内在的划分为了3个不同的队列(号码性质不同),每当一个用户去被服务了,那么就销毁这一个号码,每当进入一个客户,相应的增加一个号码。2)、窗口的工作人员不停的工作,他们会根据窗口的属性、根据服务对象的队列号去叫下一个人来办理业务。Vip窗口和快速窗口当本类的业务客户都处理完了,就去帮助普通窗口工作。
注意:三类客户的产生比例不同,1:3:6,用线程的周期时间来控制,没个周期内都产生一个相应类型的客户,那么把周期时间控制到1:3:6则就让用户数量呈现这个比例了。且不同的客户在办理业务时时间也是不同的,有一个范围限定,普通客户和vip客户在范围内随机,快速用户为最小办理时间,sleep模拟。
2、类规划:
NumberMachine:取号机,一个大厅只有一个取号机,所以单例实现。同时该取号机内存在三种号码管理器,分别对应三种客户的号码管理。同时使用线程提供三种号码管理器的业务工作,即产生用户。
NumberManage:虽然有三种用户,但是他们产生号码的号码管理器工作方式都是一样的,封装成一个类,在NumberMachine中创建3个对象即可;使用一个List属性存放用户编号。提供添加用户的方法。提供获取队列最首用户的方法给窗口业务员去调用。
ServiceWindow:提供一个ID属性和TYPE属性(类型显然是枚举),同时为该两种属性提供set方法,而不是在构造器中绑定ID和TYPE,更符合实际情况,因为窗口实际生活中可以改变属性的。该类还根据3种窗口类型分别3种业务处理方法,使用线程实现,不停叫号工作。
CustomerType:枚举类,为ServiceWindow的TYPE属性提供值。方便使用,重写toString方法,
Constants:常量类,存放系统中使用的常量。
BankSystem:系统工作类。
3、具体实现:
NumberManager.java
package blog13Bank;
import java.util.ArrayList;
import java.util.List;
// 号码管理器,用户号码产生的类
public class NumberManager {
private int lastNumber = 0;
private List<Integer> queue = new ArrayList<>();
public synchronized Integer newCustomer(){ /*设置成线程锁的方法,因为该方法用NumberMachine的对象调用
而叫号去办理用户的方法由ServiceWindow窗口类调用,不同类共同访问queue会线程安全问题,所以加锁*/
queue.add(++lastNumber);
return lastNumber;
}
public synchronized Integer fetchNumber(){
if(queue.size()>0){
return queue.remove(0); //取走队首元素,
}
return null;//队列为空,没有用户,就返回null4,所以方法返回值需要设置成Integer
}
}
NumberMachine.java
package blog13Bank;
// 取号机,是一个单例,先当普通类实现业务,再将类写成单例
public class NumberMachine {
private NumberManager commonManager = new NumberManager();
private NumberManager expressManager = new NumberManager();
private NumberManager vipManager = new NumberManager();
//创建三个号码管理器,并提供get获取方法
public NumberManager getCommonManager() {
return commonManager;
}
public NumberManager getExpressManager() {
return expressManager;
}
public NumberManager getVipManager() {
return vipManager;
}
//写成单例
private NumberMachine(){}
private static NumberMachine instance = new NumberMachine();
public static NumberMachine getInstance(){
return instance;
}
//取号机的业务可以用线程写在构造器中,意味着一创造出来就不停工作了,也可以在其他类中使用到取号机再写业务
//本例放到BankSystem类中开始工作时为取号机指定业务:使用定时器固定频率工作,造成用户比例1:3:6
}
ServiceWindow.java
package blog13Bank;
import java.util.Random;
import java.util.concurrent.Executors;
//银行的窗口类
//我自己的思路:写一个模板父类window:提供protected属性和一个抽象的work方法,然后三种窗口为其三种子类,重写其work方法即可
public class ServiceWindow {
private int ID = 1; //默认为1号窗口
private WindowType type = WindowType.COMMON;//默认为普通窗口
//提供属性设置方法,用于创建不同类型的窗口
public void setID(int iD) {
ID = iD;
}
public void setType(WindowType type) {
this.type = type;
}
//工作业务,线程编写,使其不停的叫号工作。
public void work(){
Executors.newSingleThreadExecutor().execute(new Runnable(){
@Override
public void run() {
switch(type){//根据窗口类型不同,有不同的业务处理方式
case COMMON:
while(true){
commonService();
}
case EXPRESS:
while(true){
expressService();
}
case VIP:
while(true){
vipService();
}
}
}});
}
//业务流程:窗口叫号
public void commonService(){
String name = type/*调用枚举的toString*/ + ":第 " + ID + " 号窗口";
Integer number = NumberMachine.getInstance().getCommonManager().fetchNumber();
System.out.println(name + "开始获取 普通任务");//这个任务种类实际就和number种类也就是NmuberManager对象绑定
if(number!=null){//叫号成功,模拟工作,模拟随机工作时间
System.out.println(name + "获取 普通任务 成功,"+ name + "正在为第 " + number + " 号 普通客户 服务");
int runTime = new Random().nextInt(Constants.RANDOM_FOR_WORK)+1+Constants.MIN_WORK_TIME;
try {
Thread.sleep(runTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "为第 " + number + " 号 普通用户 完成服务,共耗时 " + runTime/1000 + " 秒");
}else{//叫号失败,没有客户了
System.out.println(name + "没有取到 普通任务,空闲一秒...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void expressService(){
String name = type/*调用枚举的toString*/ + ":第 " + ID + " 号窗口";
Integer number = NumberMachine.getInstance().getExpressManager().fetchNumber();
System.out.println(name + "开始获取 快速任务");//这个任务种类实际就和number种类也就是NmuberManager对象绑定
if(number!=null){//叫号成功,模拟工作,模拟随机工作时间
System.out.println(name + "获取 快速任务 成功,"+ name + "正在为第 " + number + " 号 快速客户 服务");
int runTime = Constants.MIN_WORK_TIME;
try {
Thread.sleep(runTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "为第 " + number + " 号 快速用户 完成服务,共耗时 " + runTime/1000 + " 秒");
}else{//叫号失败,没有客户了
System.out.println(name + "没有取到 快速任务...");
commonService();
}
}
public void vipService(){
String name = type/*调用枚举的toString*/ + ":第 " + ID + " 号窗口";
Integer number = NumberMachine.getInstance().getVipManager().fetchNumber();
System.out.println(name + "开始获取 VIP任务");//这个任务种类实际就和number种类也就是NmuberManager对象绑定
if(number!=null){//叫号成功,模拟工作,模拟随机工作时间
System.out.println(name + "获取 VIP任务 成功,"+ name + "正在为第 " + number + " 号 VIP客户 服务");
int runTime = new Random().nextInt(Constants.RANDOM_FOR_WORK)+1+Constants.MIN_WORK_TIME;
try {
Thread.sleep(runTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "为第 " + number + " 号 VIP用户 完成服务,共耗时 " + runTime/1000 + " 秒");
}else{//叫号失败,没有客户了
System.out.println(name + "没有取到 VIP任务...");
commonService();
}
}
}
WindowType.java
package blog13Bank;
public enum WindowType {
COMMON,EXPRESS,VIP;
@Override
public String toString() {
String name = null;
switch(this){
case COMMON:
name = "普通";
break;
case EXPRESS:
name = "快速";
break;
case VIP:
name = this.name();
break;
}
return name;
}
}
Constants.java
package blog13Bank;
public class Constants {
public static int MIN_WORK_TIME = 1000; //最小业务办理时限1000毫秒
public static int MAX_WORK_TIME = 10000;//最大业务办理时间10000毫秒
public static int RANDOM_FOR_WORK = 10000-1000;//业务时间范围
}
BankSystem.java
package blog13Bank;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class BankSystem {
public static void main(String[] args) {
//创建6个窗口
for(int i=1;i<=4;i++){
ServiceWindow window = new ServiceWindow();
window.setID(i);
window.work();
}
ServiceWindow window = new ServiceWindow();
window.setType(WindowType.EXPRESS);
window.work();
window = new ServiceWindow();
window.setType(WindowType.VIP);
window.work();
//创建NumberMachine对象,因为是单例,不用创对象了,并为之编写业务代码
//三个线程产生3种用户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
Integer number = NumberMachine.getInstance().
getCommonManager().newCustomer();
System.out.println("第 " + number + " 位普通用户进入大厅,等待服务...");
}
},
0,
1,
TimeUnit.SECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
Integer number = NumberMachine.getInstance().
getExpressManager().newCustomer();
System.out.println("第 " + number + " 位快速用户进入大厅,等待服务...");
}
},
0,
3/*快速用户周期为3秒*/,
TimeUnit.SECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
Integer number = NumberMachine.getInstance().
getVipManager().newCustomer();
System.out.println("第 " + number + " 位VIP用户进入大厅,等待服务...");
}
},
0,
6/*vip用户周期为6秒*/,
TimeUnit.SECONDS);
}
}
运行效果:
普通:第 1 号窗口开始获取 普通任务
普通:第 1 号窗口没有取到 普通任务,空闲一秒...
普通:第 3 号窗口开始获取 普通任务
普通:第 3 号窗口没有取到 普通任务,空闲一秒...
快速:第 1 号窗口开始获取 快速任务
快速:第 1 号窗口没有取到 快速任务...
快速:第 1 号窗口开始获取 普通任务
快速:第 1 号窗口没有取到 普通任务,空闲一秒...
普通:第 2 号窗口开始获取 普通任务
普通:第 2 号窗口没有取到 普通任务,空闲一秒...
普通:第 4 号窗口开始获取 普通任务
普通:第 4 号窗口没有取到 普通任务,空闲一秒...
第 1 普通用户进入大厅,等待服务...
VIP:第 1 号窗口开始获取 VIP任务
VIP:第 1 号窗口没有取到 VIP任务...
VIP:第 1 号窗口开始获取 普通任务
VIP:第 1 号窗口获取 普通任务 成功,VIP:第 1 号窗口正在为第 1 号 普通客户 服务
第 1 快速用户进入大厅,等待服务...
第 1 VIP用户进入大厅,等待服务...
普通:第 1 号窗口开始获取 普通任务
普通:第 1 号窗口没有取到 普通任务,空闲一秒...
普通:第 3 号窗口开始获取 普通任务
普通:第 3 号窗口没有取到 普通任务,空闲一秒...
普通:第 2 号窗口开始获取 普通任务
普通:第 2 号窗口没有取到 普通任务,空闲一秒...
快速:第 1 号窗口开始获取 快速任务
快速:第 1 号窗口获取 快速任务 成功,快速:第 1 号窗口正在为第 1 号 快速客户 服务
普通:第 4 号窗口开始获取 普通任务
普通:第 4 号窗口没有取到 普通任务,空闲一秒...
第 2 普通用户进入大厅,等待服务...
普通:第 1 号窗口开始获取 普通任务
普通:第 1 号窗口获取 普通任务 成功,普通:第 1 号窗口正在为第 2 号 普通客户 服务
普通:第 2 号窗口开始获取 普通任务
普通:第 2 号窗口没有取到 普通任务,空闲一秒...
普通:第 4 号窗口开始获取 普通任务
普通:第 4 号窗口没有取到 普通任务,空闲一秒...
第 3 普通用户进入大厅,等待服务...
普通:第 3 号窗口开始获取 普通任务
普通:第 3 号窗口获取 普通任务 成功,普通:第 3 号窗口正在为第 3 号 普通客户 服务
快速:第 1 号窗口为第 1 号 快速用户 完成服务,共耗时 1 秒
快速:第 1 号窗口开始获取 快速任务
快速:第 1 号窗口没有取到 快速任务...
快速:第 1 号窗口开始获取 普通任务
快速:第 1 号窗口没有取到 普通任务,空闲一秒...
普通:第 2 号窗口开始获取 普通任务
普通:第 2 号窗口没有取到 普通任务,空闲一秒...
第 4 普通用户进入大厅,等待服务...
第 2 快速用户进入大厅,等待服务...
普通:第 4 号窗口开始获取 普通任务
普通:第 4 号窗口获取 普通任务 成功,普通:第 4 号窗口正在为第 4 号 普通客户 服务
快速:第 1 号窗口开始获取 快速任务
快速:第 1 号窗口获取 快速任务 成功,快速:第 1 号窗口正在为第 2 号 快速客户 服务
普通:第 2 号窗口开始获取 普通任务
普通:第 2 号窗口获取 普通任务 成功,普通:第 2 号窗口正在为第 5 号 普通客户 服务
第 5 普通用户进入大厅,等待服务...
快速:第 1 号窗口为第 2 号 快速用户 完成服务,共耗时 1 秒
快速:第 1 号窗口开始获取 快速任务
快速:第 1 号窗口没有取到 快速任务...
快速:第 1 号窗口开始获取 普通任务
快速:第 1 号窗口没有取到 普通任务,空闲一秒...
VIP:第 1 号窗口为第 1 号 普通用户 完成服务,共耗时 4 秒
VIP:第 1 号窗口开始获取 VIP任务
VIP:第 1 号窗口获取 VIP任务 成功,VIP:第 1 号窗口正在为第 1 号 VIP客户 服务
普通:第 3 号窗口为第 3 号 普通用户 完成服务,共耗时 2 秒
普通:第 3 号窗口开始获取 普通任务
普通:第 3 号窗口没有取到 普通任务,空闲一秒...
第 6 普通用户进入大厅,等待服务...
快速:第 1 号窗口开始获取 快速任务
快速:第 1 号窗口没有取到 快速任务...
快速:第 1 号窗口开始获取 普通任务
快速:第 1 号窗口获取 普通任务 成功,快速:第 1 号窗口正在为第 6 号 普通客户 服务
普通:第 3 号窗口开始获取 普通任务
普通:第 3 号窗口没有取到 普通任务,空闲一秒...
第 7 普通用户进入大厅,等待服务...
第 3 快速用户进入大厅,等待服务...
第 2 VIP用户进入大厅,等待服务...
普通:第 3 号窗口开始获取 普通任务
普通:第 3 号窗口获取 普通任务 成功,普通:第 3 号窗口正在为第 7 号 普通客户 服务
快速:第 1 号窗口为第 6 号 普通用户 完成服务,共耗时 1 秒
快速:第 1 号窗口开始获取 快速任务
快速:第 1 号窗口获取 快速任务 成功,快速:第 1 号窗口正在为第 3 号 快速客户 服务
第 8 普通用户进入大厅,等待服务...
快速:第 1 号窗口为第 3 号 快速用户 完成服务,共耗时 1 秒
快速:第 1 号窗口开始获取 快速任务
快速:第 1 号窗口没有取到 快速任务...
快速:第 1 号窗口开始获取 普通任务
快速:第 1 号窗口获取 普通任务 成功,快速:第 1 号窗口正在为第 8 号 普通客户 服务
普通:第 1 号窗口为第 2 号 普通用户 完成服务,共耗时 5 秒
普通:第 1 号窗口开始获取 普通任务
普通:第 1 号窗口没有取到 普通任务,空闲一秒...
第 9 普通用户进入大厅,等待服务...
VIP:第 1 号窗口为第 1 号 VIP用户 完成服务,共耗时 4 秒
VIP:第 1 号窗口开始获取 VIP任务
VIP:第 1 号窗口获取 VIP任务 成功,VIP:第 1 号窗口正在为第 2 号 VIP客户 服务
普通:第 1 号窗口开始获取 普通任务
普通:第 1 号窗口获取 普通任务 成功,普通:第 1 号窗口正在为第 9 号 普通客户 服务
第 10 普通用户进入大厅,等待服务...
第 4 快速用户进入大厅,等待服务...
第 11 普通用户进入大厅,等待服务...
相关文章
- 暂无相关文章
用户点评