需求:


银行业务调度系统




模拟实现银行业务调度系统逻辑,具体需求如下:


 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。


 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。


 异步随机生成各种类型的客户,生成各类型用户的概率比例为:


        VIP客户 :普通客户 :快速客户  =  1 :6 :3。


 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。


 各类型客户在其对应窗口按顺序依次办理业务。 


 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。


 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。


 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。




补充:


   银行可能会出现vip的窗口正在办理一个vip用户的业务,而普通窗口此时空闲,那么再来一个vip用户(不管是什么用户),他应该是可以去普通窗口办理业务的#



   我的核心处理逻辑就是,有一个WindowList,它里面持有者所有的Winodw(就是银行的服务窗口),它有getIdelVIPWindow,getIdelNormalWindow等方法,顾名思义,getIdelVIPWindow就是获取现在空闲的一个VIP窗口#(Window里面有一个字段是isBusy,是boolean型的)



   有一个Produce,它负责按照1:6:3的比例产生各种客户,分别放到normals,vips,quicks等3个队列



   Consumer就是一个个客户,它有execute方法#顾客去柜台办理业务的时候,所花的时间和柜台没有关系,只和自己的业务相关#因此,execute里面会根据consumer的type来决定线程sleep多长时间



   调度器就是dispatcher,它调用Produce不断生成客户,通过WindowList获得一个空闲的窗口,让这个窗口去"叫"自己对应的顾客#例如一个空闲的vip窗口,就会先去vip队列里找人,如果vip队列里面没有人,窗口就会去quick队列找人....



   类图如下:


银行业务调度系统的实现_sed



   代码如下:




 

package bank;


/**
* This class is used for ...
* @author dlf(460795365@qq.com)
* @version 1.0, 2017年2月21日 下午10:10:46
*/
public class Consumer {


public Integer id;
public String type;

public Consumer(Integer id,String type){
this.id=id;
this.type=type;
}

public void execute(){
try{
if (type.equals("normal")) {
Thread.sleep(1000);
return ;
}
if (type.equals("quick")) {
Thread.sleep(300);
return ;
}
if (type.equals("vip")) {
Thread.sleep(1000);
return ;
}
}catch(Exception exception){
exception.printStackTrace();
}

}

}


package bank;


/**
* This class is used for ...
*
* @author dlf(460795365@qq.com)
* @version 1.0, 2017年2月21日 下午6:50:55
*/
public abstract class Window {


public int id;
public String type;
public Boolean isBusy;


public void execute(Consumer client) {
System.out.println(id + "号" + type + "业务员 开始办理" + client.id + "号" + client.type + "顾客的业务");
isBusy = true;
client.execute();
isBusy = false;
System.out.println(id + "号normal业务员 办理完了" + client.id + "号" + client.type + "顾客的业务");
}
}


class WindowForVIP extends Window {


public WindowForVIP(int i) {
id = i;
type = "vip";
isBusy = false;
}
}


class WindowForNormal extends Window {


public WindowForNormal(int i) {
id = i;
type = "normal";
isBusy = false;
}


}


class WindowForQuick extends Window {


public WindowForQuick(int i) {
id = i;
type = "quick";
isBusy = false;
}


}



package bank;


import java.util.ArrayList;
import java.util.List;


/**
* This class is used for ...
* @author dlf(460795365@qq.com)
* @version 1.0, 2017年2月21日 下午7:55:34
*/
public class WindowList {
public List<WindowForNormal> normallist=new ArrayList<>();
public List<WindowForVIP> viplist=new ArrayList<>();
public List<WindowForQuick> quicklist=new ArrayList<>();

public WindowList(){
for(int i=1;i<5;i++)
normallist.add(new WindowForNormal(i));

quicklist.add(new WindowForQuick(5));
viplist.add(new WindowForVIP(6));
}

public Window getIdelVIPWindow(){
for(Window s:viplist){
if(!s.isBusy){
return s;
}
}
return null;
}

public Window getIdelNormalWindow(){
for(Window s:normallist){
if(!s.isBusy){
return s;
}
}
return null;
}

public Window getIdelQuickWindow(){
for(Window s:quicklist){
if(!s.isBusy){
return s;
}
}
return null;
}

}



package bank;


import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;


/**
* This class is used for ...
* @author dlf(460795365@qq.com)
* @version 1.0, 2017年2月21日 下午7:01:18
*/
public class Producer {


//省略get/set方法
public ArrayBlockingQueue<Consumer> normals;
public ArrayBlockingQueue<Consumer> vips;
public ArrayBlockingQueue<Consumer> quicks;


public void produce(){
Random random=new Random();
Random time=new Random();
int i=1;
try {

while (true) {
//产生1-10
int type=random.nextInt(10)+1;
if (type==1) {
System.out.println("产生第"+i+"个客户,他是vip用户");
vips.put(new Consumer(i++, "vip"));
}else if (type<5) {
System.out.println("产生第"+i+"个客户,他是快速用户");
quicks.put(new Consumer(i++, "快速"));
}else {
System.out.println("产生第"+i+"个客户,他是普通用户");
normals.put(new Consumer(i++, "普通"));
}

Thread.sleep(time.nextInt(1000));
}


} catch (Exception e) {
// TODO: handle exception
}

}
}



下面就是最核心的分发器,就是指派某个窗口处理某个顾客的逻辑

package bank;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
* This class is used for ...
*
* @author dlf(460795365@qq.com)
* @version 1.0, 2017年2月21日 下午7:14:18
*/
public class Dispatcher {

/**
* @param threadPool
* @param Windows
* @param vips
* @param normals
* @param quicks
*/
public void doQuick(ExecutorService threadPool, WindowList Windows,
ArrayBlockingQueue<Consumer> vips,
ArrayBlockingQueue<Consumer> normals, ArrayBlockingQueue<Consumer> quicks) {
try {
while (true) {
// do vip
final Window window = Windows.getIdelQuickWindow();
if (window != null) {

int flag = 0;

final Consumer id_quick = quicks.poll(10, TimeUnit.MILLISECONDS);
if (id_quick != null)
// quick里面有人
run(window, id_quick, threadPool);
flag = 1;

if (flag == 0) {
final Consumer id_vip = vips.poll(10, TimeUnit.MILLISECONDS);
if (id_vip != null)
// quick里面没人 vip队伍里有人排队
run(window, id_vip, threadPool);
flag = 1;

}
if (flag == 0) {
final Consumer id_normal = normals.poll(10, TimeUnit.MILLISECONDS);
if (id_normal != null) {
// quick也没有人 vip队伍里没人排队 normal 里面有人
run(window, id_normal, threadPool);
}

}
} else {
// vip窗口正在忙
Thread.sleep(1000);
}

}

} catch (Exception e) {
e.printStackTrace();
}

}

/**
* @param id_quick
* @param threadPool
*/
private static void run(final Window window, final Consumer consumer, ExecutorService threadPool) {
threadPool.execute(new Runnable() {
public void run() {
window.execute(consumer);
}
});

}

/**
* @param threadPool
* @param list
* @param vips
*/
public void doNomal(ExecutorService threadPool, WindowList list, ArrayBlockingQueue<Consumer> vips,
ArrayBlockingQueue<Consumer> normals, ArrayBlockingQueue<Consumer> quicks) {

try {
while (true) {
// do vip
final Window window = list.getIdelNormalWindow();
if (window != null) {

int flag = 0;

final Consumer id_normal = normals.poll(10, TimeUnit.MILLISECONDS);
if (id_normal != null)
// normal 里面有人
run(window, id_normal, threadPool);
flag = 1;

if (flag == 0) {
final Consumer id_quick = quicks.poll(10, TimeUnit.MILLISECONDS);
if (id_quick != null)
// normal里面没人 quick里面有人
run(window, id_quick, threadPool);
flag = 1;
}

if (flag == 0) {
final Consumer id_vip = vips.poll(10, TimeUnit.MILLISECONDS);
if (id_vip != null)
// normal里面没人 normal里面没人 vip队伍里有人排队
run(window, id_vip, threadPool);
flag = 1;

}
} else {
// normal窗口正在忙
Thread.sleep(1000);
}

}

} catch (Exception e) {
e.printStackTrace();
}

}

/**
* @param vips
* @param list
* @param threadPool
* @param quicks
* @param normals
*
*/
public void doVIP(ExecutorService threadPool, WindowList list, ArrayBlockingQueue<Consumer> vips,
ArrayBlockingQueue<Consumer> normals, ArrayBlockingQueue<Consumer> quicks) {

try {
while (true) {
// do vip
final Window window = list.getIdelVIPWindow();
if (window != null) {
// vip窗口空闲
// System.out.println("vips is null? "+vips==null);
final Consumer id_vip = vips.poll(10, TimeUnit.MILLISECONDS);

int flag = 0;
if (id_vip != null) {
// vip队伍里有人排队
run(window, id_vip, threadPool);
flag = 1;
}

if (flag == 0) {
final Consumer id_quick = quicks.poll(10, TimeUnit.MILLISECONDS);
if (id_quick != null)
// vip队伍里没人排队 quick里面有人
run(window, id_quick, threadPool);
flag = 1;

}

if (flag == 0) {
final Consumer id_normal = normals.poll(10, TimeUnit.MILLISECONDS);
if (id_normal != null)
// vip队伍里没人排队 quick也里面有人 normal 里面有人
run(window, id_normal, threadPool);

}

} else {
// vip窗口正在忙
Thread.sleep(1000);
}

}

} catch (Exception e) {
e.printStackTrace();
}

}

}


OK,我们看看测试代码

package bank;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
* This class is used for ...
* @author dlf(460795365@qq.com)
* @version 1.0, 2017年2月22日 下午5:22:01
*/
public class Main {

public static void main(String[] args) {

final ExecutorService threadPool = Executors.newCachedThreadPool();

// 每个队伍 最多有10人
final ArrayBlockingQueue<Consumer> normals = new ArrayBlockingQueue<>(10);
final ArrayBlockingQueue<Consumer> vips = new ArrayBlockingQueue<>(10);
final ArrayBlockingQueue<Consumer> quicks = new ArrayBlockingQueue<>(10);

final WindowList Windows = new WindowList();

final Dispatcher dispatcher=new Dispatcher();
final Producer producer = new Producer();
producer.setNormals(normals);
producer.setQuicks(quicks);
producer.setVips(vips);

threadPool.execute(new Runnable() {
public void run() {
producer.produce();
}
});

threadPool.execute(new Runnable() {
public void run() {
dispatcher.doVIP(threadPool, Windows, vips, normals, quicks);
}
});

threadPool.execute(new Runnable() {
public void run() {
dispatcher.doQuick(threadPool, Windows, vips, normals, quicks);
}
});

threadPool.execute(new Runnable() {
public void run() {
dispatcher.doNomal(threadPool, Windows, vips, normals, quicks);
}
});

threadPool.execute(new Runnable() {
public void run() {

try {
while (true) {
/
int threadCount = ((ThreadPoolExecutor) threadPool).getActiveCount();
System.out.println("现在活跃的线程数量为: " + threadCount);
System.out.println("现在排队的人数为:" + (vips.size() + normals.size() + quicks.size()));
Thread.sleep(3000);
}
} catch (Exception e) {
e.printStackTrace();
}

}
});

}
}
最后的打印出来的信息如下:
产生第1个客户,他是快速用户
现在活跃的线程数量为: 5
现在排队的人数为:0
5号quick业务员 开始办理1号快速顾客的业务
5号normal业务员 办理完了1号快速顾客的业务
产生第2个客户,他是普通用户
1号normal业务员 开始办理2号普通顾客的业务
1号normal业务员 办理完了2号普通顾客的业务
产生第3个客户,他是快速用户
5号quick业务员 开始办理3号快速顾客的业务
5号normal业务员 办理完了3号快速顾客的业务
产生第4个客户,他是普通用户
1号normal业务员 开始办理4号普通顾客的业务
1号normal业务员 办理完了4号普通顾客的业务
产生第5个客户,他是快速用户
5号quick业务员 开始办理5号快速顾客的业务
5号normal业务员 办理完了5号快速顾客的业务
现在活跃的线程数量为: 5
现在排队的人数为:0
产生第6个客户,他是普通用户
1号normal业务员 开始办理6号普通顾客的业务
1号normal业务员 办理完了6号普通顾客的业务
产生第7个客户,他是快速用户
5号quick业务员 开始办理7号快速顾客的业务
5号normal业务员 办理完了7号快速顾客的业务
产生第8个客户,他是快速用户
5号quick业务员 开始办理8号快速顾客的业务
5号normal业务员 办理完了8号快速顾客的业务
产生第9个客户,他是普通用户
1号normal业务员 开始办理9号普通顾客的业务
1号normal业务员 办理完了9号普通顾客的业务
产生第10个客户,他是快速用户
5号quick业务员 开始办理10号快速顾客的业务
5号normal业务员 办理完了10号快速顾客的业务
产生第11个客户,他是普通用户
1号normal业务员 开始办理11号普通顾客的业务
1号normal业务员 办理完了11号普通顾客的业务
现在活跃的线程数量为: 5
现在排队的人数为:0
产生第12个客户,他是普通用户
1号normal业务员 开始办理12号普通顾客的业务
1号normal业务员 办理完了12号普通顾客的业务
产生第13个客户,他是快速用户
5号quick业务员 开始办理13号快速顾客的业务
5号normal业务员 办理完了13号快速顾客的业务
产生第14个客户,他是普通用户
1号normal业务员 开始办理14号普通顾客的业务
1号normal业务员 办理完了14号普通顾客的业务
产生第15个客户,他是普通用户
1号normal业务员 开始办理15号普通顾客的业务
1号normal业务员 办理完了15号普通顾客的业务
产生第16个客户,他是普通用户
1号normal业务员 开始办理16号普通顾客的业务
1号normal业务员 办理完了16号普通顾客的业务
现在活跃的线程数量为: 5
现在排队的人数为:0
产生第17个客户,他是快速用户
5号quick业务员 开始办理17号快速顾客的业务
5号normal业务员 办理完了17号快速顾客的业务
产生第18个客户,他是普通用户
1号normal业务员 开始办理18号普通顾客的业务
1号normal业务员 办理完了18号普通顾客的业务
产生第19个客户,他是普通用户
1号normal业务员 开始办理19号普通顾客的业务
1号normal业务员 办理完了19号普通顾客的业务
产生第20个客户,他是普通用户
1号normal业务员 开始办理20号普通顾客的业务
1号normal业务员 办理完了20号普通顾客的业务
产生第21个客户,他是快速用户
5号quick业务员 开始办理21号快速顾客的业务
5号normal业务员 办理完了21号快速顾客的业务
产生第22个客户,他是普通用户
1号normal业务员 开始办理22号普通顾客的业务
1号normal业务员 办理完了22号普通顾客的业务
现在活跃的线程数量为: 5
现在排队的人数为:0
产生第23个客户,他是普通用户
1号normal业务员 开始办理23号普通顾客的业务
1号normal业务员 办理完了23号普通顾客的业务
产生第24个客户,他是普通用户
1号normal业务员 开始办理24号普通顾客的业务
1号normal业务员 办理完了24号普通顾客的业务
产生第25个客户,他是普通用户
1号normal业务员 开始办理25号普通顾客的业务
1号normal业务员 办理完了25号普通顾客的业务
产生第26个客户,他是普通用户
1号normal业务员 开始办理26号普通顾客的业务
1号normal业务员 办理完了26号普通顾客的业务
产生第27个客户,他是快速用户
6号vip业务员 开始办理27号快速顾客的业务
6号normal业务员 办理完了27号快速顾客的业务
产生第28个客户,他是普通用户
1号normal业务员 开始办理28号普通顾客的业务
1号normal业务员 办理完了28号普通顾客的业务
现在活跃的线程数量为: 5
现在排队的人数为:0
产生第29个客户,他是普通用户
1号normal业务员 开始办理29号普通顾客的业务
1号normal业务员 办理完了29号普通顾客的业务
产生第30个客户,他是普通用户
1号normal业务员 开始办理30号普通顾客的业务
1号normal业务员 办理完了30号普通顾客的业务
产生第31个客户,他是普通用户
1号normal业务员 开始办理31号普通顾客的业务
1号normal业务员 办理完了31号普通顾客的业务
产生第32个客户,他是快速用户
5号quick业务员 开始办理32号快速顾客的业务
5号normal业务员 办理完了32号快速顾客的业务
产生第33个客户,他是普通用户
1号normal业务员 开始办理33号普通顾客的业务
1号normal业务员 办理完了33号普通顾客的业务
现在活跃的线程数量为: 5
现在排队的人数为:0
产生第34个客户,他是快速用户
6号vip业务员 开始办理34号快速顾客的业务
6号normal业务员 办理完了34号快速顾客的业务
产生第35个客户,他是普通用户
1号normal业务员 开始办理35号普通顾客的业务
1号normal业务员 办理完了35号普通顾客的业务
产生第36个客户,他是普通用户
1号normal业务员 开始办理36号普通顾客的业务
1号normal业务员 办理完了36号普通顾客的业务
产生第37个客户,他是普通用户
1号normal业务员 开始办理37号普通顾客的业务
1号normal业务员 办理完了37号普通顾客的业务
现在活跃的线程数量为: 5
现在排队的人数为:0
产生第38个客户,他是普通用户
1号normal业务员 开始办理38号普通顾客的业务
1号normal业务员 办理完了38号普通顾客的业务
产生第39个客户,他是快速用户
5号quick业务员 开始办理39号快速顾客的业务
5号normal业务员 办理完了39号快速顾客的业务
产生第40个客户,他是vip用户
6号vip业务员 开始办理40号vip顾客的业务
产生第41个客户,他是普通用户
1号normal业务员 开始办理41号普通顾客的业务
1号normal业务员 办理完了41号普通顾客的业务
6号normal业务员 办理完了40号vip顾客的业务
现在活跃的线程数量为: 5
现在排队的人数为:0