天天看点

银行调度系统详解

1、需求分析

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

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

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

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

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

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

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

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

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

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

2、思路

(1)银行的每个客户是通过一个取号器获取的一个号码,而不同种类的客户的编号不一样,但都是同意台机器,

(2)那我们不难想出了,先模拟区号机,但是想模拟取号机,就先要模拟取号器,因为一个取号机里面有几个不同的取号器,分别对应不同的客户类型

(3)那我们就先描述取号器,再在取号机里面创建三个取号器对象,而本系统中,取号器只需一个,所以要设计成单例

(4)在定义一个窗口类,并在类中完成对客户的服务

(5)在启动类中,创建相应的窗口,并模拟各种客户类型的人到来

3、取号器

(1)定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。

(2)定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步。

package com.ren.bank;

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

/**
 *
 * @author renpingqing
 */
public class NumberManager {
	//定义一个容器模拟排队的人
	private List<Integer> queues = new ArrayList<Integer>();
	
	//表示最后一个取的号
	private Integer lastNum = 1;
	
	//获取要服务的号码
	public Integer getServiceNum() {
		Integer in = null;
		if(queues.size() > 0) {
			 in = queues.remove(0);
		}
		return in;
	}
	
	//客户要取的号码
	public Integer getNum() {
		queues.add(lastNum);
		return lastNum++;
	}
	
}
           

4、管理取号器的机器

(1) 定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,定义三个对应的方法来返回这三个NumberManager对象。

(2)因为取号器只有一个,所以将NumberMachine类设计成单例。

package com.ren.bank;
/**
 *
 * @author renpingqing
 */
public class NumberMachine {
	//创建三个取号器,分别表示普通客户,快速客户,vip客户
	private NumberManager common = new NumberManager();
	private NumberManager quick = new NumberManager();
	private NumberManager vip = new NumberManager();
	
	public NumberManager getCommon() {
		return common;
	}
	public NumberManager getQuick() {
		return quick;
	}
	public NumberManager getVip() {
		return vip;
	}
	
	//单例
	public static NumberMachine getInstance() {
		return instance;
	}
	private static NumberMachine instance = new NumberMachine();
}
           

5、客户的类型

该系统有三种客户类型,所以定义成枚举,并覆盖toString方法以返回我们所熟悉的表现方式

package com.ren.bank;
/**
 *
 * @author renpingqing
 */
public enum ClientType {
	COMMON,QUICK,VIP;
	
	//覆盖秋toString方法,以获得更好的表现形式
	public String toString() {
		switch(this) {
		case COMMON:
			return "普通客户";
		case QUICK:
			return "快速客户";
		case VIP:
			return name();
		}
		return null;
	}
}
           

6、服务窗口

在start方法中新开一个线程,根据客户的类型,拿到对应的取号器,并取出一个正在排队的客户,为改口客户而服务

package com.ren.bank;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 *
 * @author renpingqing
 */
public class ServiceWindow {
	
	//窗口类型
	private ClientType type = ClientType.COMMON;
	
	//窗口编号
	private int windowNum = 1;
	
	public void setType(ClientType type) {
		this.type = type;
	}

	public void setWindowNum(int windowNum) {
		this.windowNum = windowNum;
	}

	//开始服务方法
	public void start() {
		ExecutorService service = Executors.newSingleThreadExecutor();
		service.execute(new Runnable() {

			@Override
			public void run() {
				while(true) {
					switch(type) {
						case COMMON:
							commonService();
							break;
						case QUICK:
							quickService();
							break;
						case VIP:
							vipService();
							break;
					}
				}
			}

			
		});
	}
	
	//普通客户
	private void commonService() {
		out("--普通取号--第" + windowNum + "个" + type + "窗口在正在取号");
		Integer num = NumberMachine.getInstance().getCommon().getServiceNum();
		if(num != null) {
			out("--服务中--第" + windowNum + "个普通窗口正在为。第" + num + type + "服

务");
			long startTime = System.currentTimeMillis();
			try {
				Thread.sleep(new Random()
				.nextInt(constants.MAX_SERVICE_TIME - constants.MIN_SERVICE_TIME) + 
				constants.MIN_SERVICE_TIME + 1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			long endTime = System.currentTimeMillis();
			out("--服务完成--第" + windowNum + "个普通窗口为。第" + num + type + 
					"服务完成。耗时:" + (endTime-startTime) / 1000);
			
		} else {
			out("--没有取道号-休息1秒-第" + windowNum + "个普通窗口没有获取到任务" + "

休息一秒");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	//快速客户
		private void quickService() {
			out("--快速取号--第" + windowNum + "个" + type + "窗口在正在取号");
			Integer num = NumberMachine.getInstance().getQuick().getServiceNum();
			if(num != null) {
				out("--服务中--第" + windowNum + "个快速窗口正在为.第" + num + type + 

"服务");
				long startTime = System.currentTimeMillis();
				try {
					Thread.sleep(constants.MIN_SERVICE_TIME);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				long endTime = System.currentTimeMillis();
				out("--服务完成--第" + windowNum + "个快速窗口为.第" + num + type + 
						"服务完成。耗时:" + (endTime-startTime) / 1000);
				
			} else {
				out("--没有取道号--第" + windowNum + "个快速窗口没有取到客户");
				commonService();
			}
		}
		
		//vip客户
		private void vipService() {
			out("--vip取号--第" + windowNum + "个" + type + "窗口在正在取号");
			Integer num = NumberMachine.getInstance().getVip().getServiceNum();
			if(num != null) {
				out("--服务中--第" + windowNum + "个vip窗口正在为。第" + num + type + 

"服务");
				long startTime = System.currentTimeMillis();
				try {
					Thread.sleep(new Random()
					.nextInt(constants.MAX_SERVICE_TIME - constants.MIN_SERVICE_TIME) + 
					constants.MIN_SERVICE_TIME + 1);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				long endTime = System.currentTimeMillis();
				out("--服务完成--第" + windowNum + "个vip窗口为。第" + num + type + 
						"服务完成。耗时:" + (endTime-startTime) / 1000);
				
			} else {
				out("--没有取道号--第" + windowNum + "个vip窗口没有取到客户");
				commonService();
			}
		}
	
	//输出
	public static void out(Object obj) {
		System.out.println(obj);
	}
}
           

7、定义程序中要用到的常量类

package com.ren.bank;
/**
 *
 * @author renpingqing
 */
public class Constants {
	public static final int  MAX_SERVICE_TIME = 10000;
	public static final int MIN_SERVICE_TIME = 1000;
}
           

8、启动类

在启动类中,分别创建几个窗口,并分别模拟不同类型的客户到来!

package com.ren.bank;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author renpingqing
 */
public class Start {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//创建5个普通窗口
		for(int i=1;i<=5;i++) {
			ServiceWindow w1 = new ServiceWindow();
			w1.setWindowNum(i);
			w1.start();
		}
		
		//创建一个快速速窗口
		ServiceWindow quick1 = new ServiceWindow();
		quick1.setType(ClientType.QUICK);
		
		//创建一个vip窗口
		ServiceWindow vip1 = new ServiceWindow();
		vip1.setType(ClientType.VIP);
		
		//模拟普通客户
		ScheduledExecutorService commonTimer = Executors.newScheduledThreadPool(1);
		commonTimer.scheduleAtFixedRate(
				new Runnable() {

					@Override
					public void run() {
						Integer num = NumberMachine.getInstance().getCommon().getNum();
						out("--客户来了--第" + num +"位普通客户正在等待服务……

");
					}
				}, 
				0, 
				1, 
				TimeUnit.SECONDS
			);

		//模拟快速客户
		ScheduledExecutorService quickTimer = Executors.newScheduledThreadPool(1);
		quickTimer.scheduleAtFixedRate(
				new Runnable() {

					@Override
					public void run() {
						Integer num = NumberMachine.getInstance().getQuick().getNum();
						out("--客户来了--第" + num +"位快速客户正在等待服务……

");
					}
				}, 
				0, 
				3, 
				TimeUnit.SECONDS
			);
		
		//模拟vip客户
		ScheduledExecutorService vipTimer = Executors.newScheduledThreadPool(1);
		vipTimer.scheduleAtFixedRate(
				new Runnable() {

					@Override
					public void run() {
						Integer num = NumberMachine.getInstance().getQuick().getNum();
						out("--客户来了--第" + num +"位vip客户正在等待服务……

");
					}
				}, 
				0, 
				6, 
				TimeUnit.SECONDS
			);	

	}
	
	//输出
	public static void out(Object obj) {
		System.out.println(obj);
	}

}
           

当看完这两个项目时,突然间明白,项目不过如此,往往是我想复杂了!