---------------------- android培训、java培训、期待与您交流! ----------------------
现在我们继续探讨一下面试题系列的第二道题:银行业务调度系统,相对第一道面试题来说,这道题的逻辑较为复杂。尽管如此,祥叔还是相当的厉害,把细节分析的非常到位。
银行业务调度系统的原型取例于真实生活场景,银行共有6个业务窗口,4个普通用户窗口和1个快速窗口,和1个vip窗口,三种对应的客户比例是: vip客户:普通客户:快速客户=1:6:3。客户办理业务的时间有最大值和最小值,在该范围内随机设定每个vip客户以及普通客户办理业务所需时间,而快速窗口则时间为最小值。
当vip和快速窗口空闲时,也服务普通客户。
这三种客户对应相同的取号机器,但是对应不同的取号方法,而且每类客户的编码都完全独立,所以可以设定一个NumberManager类用来取号和生成号码,设定一个NumberMachine类来管理三种客户对应的取号方式,即在NumberMachine中创建三个NumberManager实例对象。具体代码如下:
import java.util.ArrayList;
import java.util.List;
public classNumberManager {
private int lastNumber=1;
private List<Integer> queueNumber=newArrayList<Integer>();
public synchronized IntegergenerateNumber(){
queueNumber.add(lastNumber);
return lastNumber++;
}
public synchronized IntegerfetchNumber(){
Integernumber=null;
if(queueNumber.size()>0){
number=queueNumber.remove(0);
}
return number;//这里可能返回null,如果返回值是int,则会造成空指针异常,因此把int改为Integer
}
}
public classNumberMachine {
privateNumberManager commonManager=new NumberManager();
privateNumberManager expressManager=new NumberManager();
privateNumberManager vipManager=new NumberManager();
publicNumberManager getCommonManager() {
return commonManager;
}
publicNumberManager getExpressManager() {
return expressManager;
}
publicNumberManager getVipManager() {
return vipManager;
}
//下面是单例设计模式
privateNumberMachine(){
}//把NumberMachine的构造方法私有化,提供静态方法,返回值是NumberMachine类型的
public static NumberMachinegetInstance(){
return instance;
}
private static NumberMachine instance=new NumberMachine();
}
系统中有三种类型的客户,所以定义一个枚举类,其中定义三个成员分别表示三种类型客户,而且需重写父类的toString方法,返回类型的中文名称。代码如下:
public enumCustomerType {
COMMON,EXPRESS,VIP;
public String toString(){
switch(this){
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return name();
}
return null;
}
}
至关重要的当然是服务窗口类了,它在内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法,用这三个方法分别对三种客户进行服务,为了观察运行效果,应打印出其中的细节信息。代码如下:
import java.util.Random;
import java.util.concurrent.Executors;
public classServiceWindow {
private CustomerType type=CustomerType.COMMON;
private int windowID= 1;
public void setType(CustomerTypetype) {
this.type = type;
}
public void setWindowID(int windowID) {
this.windowID = windowID;
}
public void start(){
Executors.newSingleThreadExecutor().execute(new Runnable(){
public void run(){
while(true){
/*if(type==CustomerType.COMMON){
}else{
}*/
//以上用if-else方法,下面使用switch方法
switch(type){//switch中的语句可以是枚举类型的变量,而且可以再case中省略前缀
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
});
}
private void commonService() {
StringwindowName="第"+windowID+"号"+type+"窗口";
Integernumber=NumberMachine.getInstance().getCommonManager().fetchNumber();
System.out.println(windowName+"正在获取服务任务!");
//从取号机得到实例,然后得到对应的Manager,最后调用取号方法
if(number !=null){
System.out.println(windowName+"正在为第"+number+"个"+"普通"+"客户服务");
long beginTime=System.currentTimeMillis();
int maxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
long serverTime=newRandom().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(serverTime);
}catch(InterruptedException e) {
e.printStackTrace();
}
long costTime=System.currentTimeMillis()-beginTime;
System.out.println(windowName+"为第"+number+"个"+"普通"+"客户完成服务,耗时"+costTime/1000+"秒");
}else{
System.out.println(windowName+"没有获取服务任务!空闲1秒");
try {
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
private void expressService() {
StringwindowName="第"+windowID+"号"+type+"窗口";
Integer number=NumberMachine.getInstance().getExpressManager().fetchNumber();
System.out.println(windowName+"正在获取服务任务!");
//从取号机得到实例,然后得到对应的Manager,最后调用取号方法
if(number !=null){
System.out.println(windowName+"正在为第"+number+"个"+type+"客户服务");
long beginTime=System.currentTimeMillis();
//intmaxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
//long serverTime=newRandom().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(Constants.MIN_SERVICE_TIME);
}catch(InterruptedException e) {
e.printStackTrace();
}
long costTime=System.currentTimeMillis()-beginTime;
System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒");
}else{
System.out.println(windowName+"没有获取服务任务!");
commonService();
}
}
private void vipService() {
StringwindowName="第"+windowID+"号"+type+"窗口";
Integernumber=NumberMachine.getInstance().getVipManager().fetchNumber();
System.out.println(windowName+"正在获取服务任务!");
//从取号机得到实例,然后得到对应的Manager,最后调用取号方法
if(number !=null){
System.out.println(windowName+"正在为第"+number+"个"+type+"客户服务");
long beginTime=System.currentTimeMillis();
int maxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
long serverTime=newRandom().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(serverTime);
}catch(InterruptedException e) {
e.printStackTrace();
}
long costTime=System.currentTimeMillis()-beginTime;
System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒");
}else{
System.out.println(windowName+"没有获取服务任务!");
commonService();
}
}
}
在上面的代码涉及到一个类Constants类,它的作用是定义业务服务时间的最大值和最小值,和产生普通客户的时间,并以此为基本,来得到其他两种客户的时间。代码如下:
public classConstants {
public static int MAX_SERVICE_TIME= 10000;
public static int MIN_SERVICE_TIME= 1000;
public static int COMMON_CUSTOMER_INTERVAL_TIME=1;
}
最后当然是定义MainClass类来调试和运行所写的程序,详见代码:
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class MainClass{
public static void main(String []args){
for(int i=1;i<5;i++){
ServiceWindow commonWindow=new ServiceWindow();
commonWindow.setWindowID(i);
commonWindow.start();
}
ServiceWindowexpressWindow=newServiceWindow();
expressWindow.setType(CustomerType.EXPRESS);
//expressWindow.setWindowID(5);
expressWindow.start();
ServiceWindowvipWindow=newServiceWindow();
vipWindow.setType(CustomerType.VIP);
//vipWindow.setWindowID(6);
vipWindow.start();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integernumber= NumberMachine.getInstance().getCommonManager().generateNumber();
System.out.println(number+"号普通客户等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME,
TimeUnit.SECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integernumber= NumberMachine.getInstance().getVipManager().generateNumber();
System.out.println(number+"号VIP客户等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME*6,
TimeUnit.SECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integernumber= NumberMachine.getInstance().getExpressManager().generateNumber();
System.out.println(number+"号快速客户等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME*2,
TimeUnit.SECONDS);
}
}
其中MainClass类中分别产生三种窗口并启动,然后创建定时器,按一定的周期去分别产生三种类型的客户,最后在控制台出现的结果当然是意想中的输出结果。
---------------------- android培训、java培训、期待与您交流! ----------------------