银行业务调度系统的项目需求:

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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







 面向对象的分析与设计

有三种对应类型的客户:VIP客户,普通客户,快速客户 ,异步随机生成各种类型的客户,各类型客户在其对应窗口按顺序依次办理业务 。

首先,经常在银行办理业务的人更有利于理解本系统,例如,我经常陪老婆跑银行,对银行的这个业务算是比较熟悉了,我知道每一个客户其实就是由银行的一个取号机器产生号码的方式来表示的。所以,我想到要有一个号码管理器对象,让这个对象不断地产生号码,就等于随机生成了客户。

由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。这三个号码管理器对象统一由一个号码机器进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。

各类型客户在其对应窗口按顺序依次办理业务 ,准确地说,应该是窗口依次叫号。

类图:



NumberManager和NumberMachine类





NumberManager类

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

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

NumberMachine类

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

将NumberMachine类设计成单例。





ServiceWindow与CustomerType枚举类





CustomerType枚举类

系统中有三种类型的客户,所以用定义一个枚举类,其中定义三个成员分别表示三种类型的客户。

重写toString方法,返回类型的中文名称。这是在后面编码时重构出来的,刚开始不用考虑。

ServiceWindow类

定义一个start方法,内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法。 

定义三个方法分别对三种客户进行服务,为了观察运行效果,应详细打印出其中的细节信息。

MainClass类与Constants类





MainClass类

用for循环创建出4个普通窗口,再创建出1个快速窗口和一个VIP窗口。

接着再创建三个定时器,分别定时去创建新的普通客户号码、新的快速客户号码、新的VIP客户号码。

Constants类

定义三个常量:MAX_SERVICE_TIME、MIN_SERVICE_TIME、COMMON_CUSTOMER_INTERVAL_TIME



具体代码如下:

Constants类:

public class Constants {

	public static int MAX_SERVICE_TIME=10000;//10s
	public static int MIN_SERVICE_TIME=1000;//1s
	/*每个普通窗口服务一个客户的平均时间为5秒,一共有4个这样的窗口,也就是说银行的所有普通窗口合起来
	 * 平均1.25秒内可以服务完一个普通客户,再加上快速窗口和VIP窗口也可以服务普通客户,所以,
	 * 1秒钟产生一个普通客户比较合理,*/
	public static int COMMON_CSUTOMER_INTERVAL_TIME=1;
}



 CustomerType类:

public enum CustomerType {

	COMMON,EXPRESS,VIP;

	public String toString(){
		String name=null;
		switch(this){

			case COMMON:
				return "普通";

			case EXPRESS:
				return "快速";

			case VIP:
				return name=name();//枚举中返回自己的名字

		}
		return name;
	}
}





NumberMachine类:

//一台机器产生3个号码管理器
public class NumberMachine {
	private NumberManager commonManger=new NumberManager();
	private NumberManager expressManger=new NumberManager();
	private NumberManager vipManger=new NumberManager();

	public NumberManager getCommonManger() {
		return commonManger;
	}
	public NumberManager getExpressManger() {
		return expressManger;
	}
	public NumberManager getVipManger() {
		return vipManger;
	}

	//首先做成普通对象,然后做成单例

	private NumberMachine(){}
		public static NumberMachine getInstance(){
			return instance;
		}

		private static NumberMachine instance=new NumberMachine();
		//要加静态还要加变量名。因为这个对象还没有创建

}

NumberManager类:

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

/**
 * 号码发生器
 * @author hjl
 *
 */
public class NumberManager {

	private int lastNumber=1;
	private List<Integer> queueNumber=new ArrayList<Integer>();
	//变量的类型尽量面对父级对象,如上题中的List
	public synchronized Integer generateNewManager(){//当多个线程来操作时,就会进行线程的互斥
		queueNumber.add(lastNumber);
		return lastNumber++;

	}
	//queueNumber.remove(0)返回的是Null,而定义的是int,所以要把下面的int变成Integer
	public synchronized Integer fetchServiceNumber(){//与上面的方法构成两个不同的线程,它们要访问相同的数据。
		//bug修正地方:没有对数字进行判断
		Integer number=null;
		if(queueNumber.size()>0){
			queueNumber.remove(0);
		}

		return number;
		//当要把一个集合里的某个方法拿走,拿走的方法有返回值,
		//返回值就是取出的那个号,取走它马上要用,所以返回值还是它
	}

}

ServiceWindow 类:

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

//服务窗口.叫号
public class ServiceWindow {
	//private int type;//窗口内型,利用枚举
	private CustomerType type=CustomerType.COMMON;
	private int windowId=1;
	private int number=1;

	public void setNumber(int number){
		this.number = number;
	}

	public void setType(CustomerType type) {
		this.type = type;
	}

	public void setWindowId(int windowId) {
		this.windowId = windowId;
	}

	public void start(){
		Executors.newSingleThreadExecutor().execute(new Runnable() {

			@Override
			public void run() {
				//取号
				while(true){
					//switch数据类型只能是数字类型,如long,int ,但是枚举也是没有问题的
					switch(type){
						case COMMON:

							commonService();
							break;
						case EXPRESS:

							expressService();
							break;
						case VIP:

							vipService();
							break;

					}

				}

			}

		});
		//这是一个线程池在执行一个任务。
	}

	private void commonService() {
		String windowName="第"+windowId+"号"+type+"窗口正在服务";
		System.out.println(windowName+"正在获取任务");
		Integer number=	NumberMachine.getInstance().getCommonManger().fetchServiceNumber();

		if(number!=null){
			System.out.println(windowName+"为第"+number+"个"+"普通"+"客户服务");
			long beginTime= System.currentTimeMillis();
			int maxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
			long serverTime=new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;//前面1-9000中的随机值,后面加上的话就是1-10000

			try {
				Thread.sleep(serverTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//long costTime= System.currentTimeMillis()-beginTime;
			System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+serverTime/1000+"秒");

		}else{
			System.out.println(windowName+"没有取到服务任务,先休息1秒");
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

//	private void expressService() {
//
//
//		Integer number=	NumberMachine.getInstance().getExpressManger().fetchServiceNumber();
//		String windowName="第"+windowId+"号"+type+"窗口正在服务";
//		System.out.println(windowName+"正在获取任务");
//		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=new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;//前面1-9000中的随机值,后面加上的话就是1-10000
//
//			try {
//				Thread.sleep(Constants.MIN_SERVICE_TIME);
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//			long costTime= System.currentTimeMillis()-beginTime;
//			System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒");
//
//		}else{
//			System.out.println(windowName+"没有取到服务任务");
//			commonService();
//
//		}
//	}

//	private void vipService() {
//		String windowName="第"+windowId+"号"+type+"窗口正在服务";
//		//由于三个方法都加载了同步锁,不会产生阻塞,我们可以把它放到同步锁的下面
//		Integer number=	NumberMachine.getInstance().getVipManger().fetchServiceNumber();
//		System.out.println(windowName+"正在获取任务");
//		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=new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;//前面1-9000中的随机值,后面加上的话就是1-10000
//
//			try {
//				Thread.sleep(serverTime);
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//			long costTime= System.currentTimeMillis()-beginTime;
//			System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒");
//
//		}else{
//			System.out.println(windowName+"没有取到服务任务");
//			//vip窗口没有接到任务,接着就为普通窗口完成任务
//			commonService();
//
//		}
//	}

	private void expressService(){
		Integer serviceNumber = NumberMachine.getInstance().getExpressManger().fetchServiceNumber();
		String windowName = "第" + number + "号" + type + "窗口";
		System.out.println(windowName + "开始获取快速任务!");
		if(serviceNumber !=null){
			System.out.println(windowName + "开始为第" + serviceNumber + "号快速客户服务");
			int serviceTime = Constants.MIN_SERVICE_TIME;
			try {
				Thread.sleep(serviceTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(windowName + "完成为第" + serviceNumber + "号快速客户服务,总共耗时" + serviceTime/1000 + "秒");
		}else{
			System.out.println(windowName + "没有取到快速任务!");
			commonService();
		}
	}

	private void vipService(){

		Integer serviceNumber = NumberMachine.getInstance().getVipManger().fetchServiceNumber();
		String windowName = "第" + number + "号" + type + "窗口";
		System.out.println(windowName + "开始获取VIP任务!");
		if(serviceNumber !=null){
			System.out.println(windowName + "开始为第" + serviceNumber + "号VIP客户服务");
			int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
			int serviceTime = new Random().nextInt(maxRandom)+1 + Constants.MIN_SERVICE_TIME;
			try {
				Thread.sleep(serviceTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(windowName + "完成为第" + serviceNumber + "号VIP客户服务,总共耗时" + serviceTime/1000 + "秒");
		}else{
			System.out.println(windowName + "没有取到VIP任务!");
			commonService();
		}
	}

}



 MainClass 类:

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

public class MainClass {

	public static void main(String[] args) {

		//产生4个普通窗口
		for(int i=1;i<5;i++){
			ServiceWindow commonwindow=new ServiceWindow();
			commonwindow.setWindowId(i);
			commonwindow.start();
		}
		//产生1个快速窗口
		ServiceWindow expresswindow=new ServiceWindow();
		expresswindow.setType(CustomerType.EXPRESS);
		expresswindow.start();

		//产生1个VIP窗口
		ServiceWindow vipwindow=new ServiceWindow();
		vipwindow.setType(CustomerType.VIP);
		vipwindow.start();

		//模拟客户进来,不是普通的线程池,是调度的线程池
		//普通客户拿号
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable() {

					@Override
					public void run() {
						// TODO Auto-generated method stub
						//开始叫号,首先找机器要号
						Integer number=NumberMachine.getInstance().getCommonManger().generateNewManager();
						System.out.println(number+"号普通客户等待服务!");
					}
				}, 0, Constants.COMMON_CSUTOMER_INTERVAL_TIME, TimeUnit.SECONDS);

		//快速客户拿号
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable() {

					@Override
					public void run() {
						// TODO Auto-generated method stub
						//开始叫号,首先找机器要号
					Integer number=NumberMachine.getInstance().getExpressManger().generateNewManager();
						System.out.println(number+"号快速客户等待服务!");

					}
				}, 0, Constants.COMMON_CSUTOMER_INTERVAL_TIME*2, TimeUnit.SECONDS);

		//VIP客户拿号
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable() {

					@Override
					public void run() {
						// TODO Auto-generated method stub
						//开始叫号,首先找机器要号
						Integer number=NumberMachine.getInstance().getVipManger().generateNewManager();
						System.out.println(number+"号VIP客户等待服务!");
					}
				}, 0, Constants.COMMON_CSUTOMER_INTERVAL_TIME*6, TimeUnit.SECONDS);

	}

}

java基础---Java---面试题---银行业务调度系统(线程同步锁、枚举、线程池)的更多相关文章

  1. 又一道软通动力7K月薪面试题——银行业务调度系统

    后期补充:网友对我诟病最多的就是我帮学生做面试题,说这是小偷和骗子行为,在此,我对自己给学员做面试题做出例如以下解释:  (1)学员拿着面试题来找老师,学生也事先思考和尝试后实在没有办法,又求职心切才 ...

  2. 黑马程序员——【Java高新技术】——案例:银行业务调度系统

    ---------- android培训.java培训.期待与您交流! ---------- 一.银行业务调度系统需求 Ø 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗 ...

  3. 黑马程序员:Java编程_7K面试题之银行业务调度系统

    =========== ASP.Net+Android+IOS开发..Net培训.期待与您交流!=========== 模拟实现银行业务调度系统逻辑,具体需求如下: 银行内有6个业务窗口,1 - 4号 ...

  4. Java——银行业务调度系统

     需求: 模拟实现银行业务调度系统逻辑,具体需求如下: Ø 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口. Ø 有三种对应类型的客户:VIP客户,普通 ...

  5. 40道Java基础常见面试题及详细答案

    最近看到网上流传着各种面试经验及面试题,往往都是一大堆技术题目贴上去,但是没有答案. 为此我业余时间整理了40道Java基础常见的面试题及详细答案,望各路大牛发现不对的地方不吝赐教,留言即可. 八种基 ...

  6. JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题

    JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...

  7. java基础常见面试题,这是一篇超长的随笔!!!

    1. Java基础部分....................................................... 4 1.一个".java"源文件中是否可以包括 ...

  8. Java基础常见笔试题总结

    1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件 2.“sta ...

  9. 黑马程序员_java基础笔记(15)...银行业务调度系统_编码思路及代码

    —————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流!—————————— 1,面试题目:银行业务调度系统 模拟实现银行业务调度系统逻辑,具体需求如下: 银行内 ...

随机推荐

  1. [UOJ UNR#2 黎明前的巧克力]

    来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 很奇妙的一道题 首先不难发现一个暴力做法,就是f[i]表示异或和为i的答案数,每次FWT上一个F数组,其中F[0]=1,F[ai]=2 ...

  2. [Spoj]Counting Divisors (cube)

    来自FallDream的博客,未经允许,请勿转载,谢谢. 设d(x)表示x的约数个数,求$\sum_{i=1}^{n}d(i^{3})$ There are 5 Input files. - Inpu ...

  3. idea和androidstudio的首次git配置一些问题

    网上都有很清楚的步骤 但是 都是教怎么使用 但是对第一次应用idea内部vcs的git 则很少有详细说明 首先要在网上创建个项目 然后本地git clone下来 不建议内部vcs的fetch from ...

  4. SSH构造struts2项目

    第一在pom.xml导入相应的包 (网上有很多导入多个包的教程,我缩减到一个了) <project xmlns="http://maven.apache.org/POM/4.0.0&q ...

  5. javascript templating

    JavaScript Micro-Templating I’ve had a little utility that I’ve been kicking around for some time no ...

  6. 批量录入快递地址-快宝地址服务(PHP代码示例)

    快递地址写错了怎么办?快递地址写的不详细怎么办?怎么皮批量录入收件人地址?微商怎么批量录入发件人地址?快宝地址清洗,有效的解决了寄送快递时,批量录入收件人信息.发件人信息时,纠正地址数据,不完整地址识 ...

  7. sshpass笔记

    sshpass简介 ssh登录的时候使用的是交互式输入,不能预先在命令行使用参数指定密码,sshpass就是为了解决这个问题的.sshpass提供非交互式输入密码的方式,可以用在shell脚本中自动输 ...

  8. ACM Where is the Marble?

    Description   Raju and Meena love to play with Marbles. They have got a lot of marbles with numbers ...

  9. OpenResty 执行阶段的概念和用途

    主要还是 Nginx 的执行阶段知识了,都是因为 OR 才会那么深刻, 它有些自己的阶段. 主要还是参照 春哥的 Nginx 教程 请多读几遍,如果不清楚nginx的执行阶段就无法充分利用 openr ...

  10. SQL Server 虚拟化(2)——理想的SQL Server虚拟机架构

    本文属于SQL Server虚拟化系列 搭建SQL Server虚拟机,在各个组织之间都有自己的标准和最佳实践.从第一眼看去,光物理配置就有过百种,所有的这些细微差别都有可能为后续日常管理过程中故障侦 ...