您的位置:首页 > 职场人生

【黑马程序员】银行业务调度系统

2013-08-04 09:13 274 查看
------- android培训java培训、期待与您交流!
----------

银行业务调度系统

一、需求分析

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

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

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

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

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

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

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

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

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

二、设计思路;

因为有三种不同类型的客户,每种类型的客户都是一个集合,所以创建了一个NumberManager类,因为窗口要从这个类取数据,所以这个类提供了一个remove的方法,又因为集合的remove方法可能返回空值,所以这个方法的返回值从int改成了Integer.这个类还要能增加数据,所以提供了一个generateNewNumber的方法,在这里,和交通灯管理系统的Rode类构造方法不同,Rode类是直接在构造方法中新启动线程,不断的增加数据。NumberManager类只提供了一个增加数据的方法,是再main函数中启动线程增加数据的。我觉得没什么区别。

客户类型总共有三种,快速,VIP,和普通。他们是由NumberMachine创建的,而NumberMachine只能有一个,所以使用单例来实现。这个类也实现了get三个NumberManager的方法。

服务窗口的设计。服务窗口的功能是取到号码,处理一段时间,然后处理下一个。是个循环,所以用while实现。取到号码是调用fetchNumber这个方法。取到后为了模拟现实中的处理过程,用sleep一段时间来代替。具体的时间由Random算出。如果fetchNumber方法返回个空,那么就先sleep一秒,要不就继续循环。而快窗口和VIP窗口的fetchNumber方法返回空后,会调用普通窗口的处理方法。所以这里可以用子类来实现,但为了实现能让普通窗口也变成其他俩种窗口,所以没有用继承。这样如果要修改窗口的类型,直接setCustomerType就能改变窗口的作用。

三、我的收获

通过学习银行业务调度系统,第一点:让我对单例设计模式的应用有了更深层次的理解,首先,单例模式的目的是让对象的实例在内存中存在的唯一性,类似客户取号码牌,取号这个功能就要设计成单例模式,如果多个客户同时取号,如果在内存中产生多个实例,那么取到的号牌就会混乱。
第二点:synchronized的问题,首先此系统需要用到多线程技术,多线程就要考虑到操作共享数据的情况,而synchronized锁就是解决这个问题,多个线程同时操作一个共享数据时,如果对数据进行修改,就需要用到synchronized锁,比如有一个线程正在操作一组共享数据,而又产生一个线程也要对这组数据进行操作,这时候就会出现问题,第一个线程没有执行完,第二个线程就要修改数据,会对第一个线程产生影响,可能第一个线程无法正常执行,用到synchronized锁就可以保证第一个线程未执行完成不允许其他线程对数据进行操作。
第三点:线程的2中创建方式:一个是继承Thread类,第二个是实现Runnable接口,对这两种方式有了更多的认识.

创建线程的第一种方式:继承Thread,由子类复写run方法。

创建线程的步骤:

1,定义类继承Thread类;

2,目的是复写run方法,将要让线程运行的代码都存储到run方法中;

3,通过创建Thread类的子类对象,创建线程对象;

4,调用线程的start方法,开启线程,并执行run方法。

线程状态:

新建:start()

运行:具备执行资格,同时具备执行权;

冻结:sleep(time),wait()—notify()唤醒;线程释放了执行权,同时释放执行资格;

临时阻塞状态:线程具备cpu的执行资格,没有cpu的执行权;

消亡:stop()

创建线程的第二种方式:实现一个接口Runnable。

步骤:

1,定义类实现Runnable接口。

2,覆盖接口中的run方法(用于封装线程要运行的代码)。

3,通过Thread类创建线程对象;

4,将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。

为什么要传递呢?因为要让线程对象明确要运行的run方法所属的对象。

5,调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。

四、具体实现

[java] view
plaincopy

import java.util.*;

//号码管理器类。不断产生号码,随机生成客户。

public class NumberManager {

private int lastNumber=1;//上一次返回的号码

private List<Integer> queueNumber=new ArrayList<Integer>();//存储排队的号码集合。List利于面向接口编程

public synchronized Integer generateNewManager(){//生成新客户

queueNumber.add(lastNumber);//产生一个号码就存起来

return lastNumber++;

}

public synchronized Integer fetchServiceNumber(){//取要服务的号

Integer number=null;

if(queueNumber.size()>0){

number=queueNumber.remove(0);//把第一个取走。返回值就是取得的号

}

return number;

}

//两个不同的线程调用这个对象身上的两个方法,客户来了调generateNewManager方法,窗口服务取下一个号用fetchServiceNumber方法。

//两个不同的线程访问相同的数据就会出问题。用synchronized关键字实现两个线程间互斥,这样多个线程操作就会形成互斥。

}

//管理3个号码管理器。单例模式

public class NumberMachine {

private NumberManager commonManager=new NumberManager();

private NumberManager expressManager=new NumberManager();

private NumberManager vipManager=new NumberManager();

public NumberManager getCommonManager() {

return commonManager;

}

public NumberManager getExpressManager() {

return expressManager;

}

public NumberManager getVipManager() {

return vipManager;

}

private NumberMachine(){}//构造方法私有化,单例设计模式

public static NumberMachine getInstance(){//静态方法返回自己的对象

return instance;

}

private static NumberMachine instance=new NumberMachine();

}

import java.util.Random;

import java.util.concurrent.Executors;

public class ServiceWindow {

private CustomerType type=CustomerType.COMMON;//哪种类型的窗口。默认普通

private int windowId=1;//窗口号

public void setType(CustomerType type) {

this.type = type;

}

public void setWindowId(int windowId) {

this.windowId = windowId;

}

public void start(){//开始叫号

Executors.newSingleThreadExecutor().execute(new Runnable(){//单独的线程池

public void run(){

while(true){//不停的取号

switch(type){//switch比if else效率高

case COMMON:

commonService();

break;

case EXPRESS:

expressService();

break;

case VIP:

vipService();

break;

}

}

}

private void commonService() {

String windowName="第"+windowId+"号"+type+"窗口";

Integer num=NumberMachine.getInstance().getCommonManager().fetchServiceNumber();//通过NumberMachine获得普通号码管理器,取号

System.out.println(windowName+"正在获取任务");

if(num!=null){

System.out.println(windowName+"为第"+num+"个"+"普通"+"客户服务!");//VIP窗口为普通客户服务,窗口是VIP,但客户是普通客户,所以不能用type

long beginTime=System.currentTimeMillis();

int maxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;//最大随机服务时间。9000

long serveTime=new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;//服务休息时间在1000到10000之间

try {

Thread.sleep(serveTime);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

long costTime=System.currentTimeMillis()-beginTime;

System.out.println(windowName+"为第"+num+"个"+"普通"+"客户完成服务,耗时"+costTime/1000+"秒");

}else{

System.out.println(windowName+"没有取到任务,先休息1秒");

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

private void expressService() {

String windowName="第"+windowId+"号"+type+"窗口";

Integer num=NumberMachine.getInstance().getExpressManager().fetchServiceNumber();

System.out.println(windowName+"正在获取任务");

if(num!=null){

System.out.println(windowName+"为第"+num+"个"+type+"客户服务!");

long beginTime=System.currentTimeMillis();

//int maxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;//最大随机服务时间

//long serveTime=new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;//服务休息时间在1000到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+"为第"+num+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒");

}else{

System.out.println(windowName+"没有取到任务");

commonService();//没取到快速任务,获取普通业务

}

}

private void vipService() {

String windowName="第"+windowId+"号"+type+"窗口";

Integer num=NumberMachine.getInstance().getVipManager().fetchServiceNumber();

System.out.println(windowName+"正在获取任务");

if(num!=null){

System.out.println(windowName+"为第"+num+"个"+type+"客户服务!");

long beginTime=System.currentTimeMillis();

int maxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;//最大随机服务时间

long serveTime=new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;//服务休息时间在1000到10000之间

try {

Thread.sleep(serveTime);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

long costTime=System.currentTimeMillis()-beginTime;

System.out.println(windowName+"为第"+num+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒");

}else{

System.out.println(windowName+"没有取到任务");

commonService();//没取到VIP任务,获取普通业务

}

}

});

}

}

public enum CustomerType {

COMMON,EXPRESS,VIP;

public String toString(){

switch(this){

case COMMON:

return "普通";

case EXPRESS:

return "快速";

case VIP:

return name();//枚举对象的name方法就是返回自己的名字

}

return null;

}

}

public class Constants {//常量类

public static int MAX_SERVICE_TIME=10000;//最大服务时间

public static int MIN_SERVICE_TIME=1000;//最小服务时间

public static int COMMOON_CUSTOMER_INTERVAL_TIME=1;//普通客户间隔时间

}

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

public class Test {

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

for(int i=1;i<5;i++){

ServiceWindow commonwindow=new ServiceWindow();

commonwindow.setWindowId(i);

commonwindow.start();//启动

}

ServiceWindow expresswindow=new ServiceWindow();

expresswindow.setType(CustomerType.EXPRESS);

expresswindow.start();

ServiceWindow vipwindow=new ServiceWindow();

vipwindow.setType(CustomerType.VIP);

vipwindow.start();

Executors.newScheduledThreadPool(1).scheduleAtFixedRate(//不是普通线程池,而是调度线程池

new Runnable(){

public void run(){

Integer number=NumberMachine.getInstance().getCommonManager().generateNewManager();//生成号码

System.out.println(number+"号普通客户正在等待服务!");

}

},

0, //过0秒来第一个客户

Constants.COMMOON_CUSTOMER_INTERVAL_TIME, //以后每隔多长时间来一个

TimeUnit.SECONDS);

Executors.newScheduledThreadPool(1).scheduleAtFixedRate(

new Runnable(){

public void run(){

Integer number=NumberMachine.getInstance().getVipManager().generateNewManager();

System.out.println(number+"号VIP客户正在等待服务!");

}

},

0,

Constants.COMMOON_CUSTOMER_INTERVAL_TIME*6,//VIP

TimeUnit.SECONDS);

Executors.newScheduledThreadPool(1).scheduleAtFixedRate(

new Runnable(){

public void run(){

Integer number=NumberMachine.getInstance().getExpressManager().generateNewManager();

System.out.println(number+"号快速客户正在等待服务!");

}

},

0,

Constants.COMMOON_CUSTOMER_INTERVAL_TIME*3,//快速

TimeUnit.SECONDS);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: