• 多线程模拟银行业务调度系统


    一、项目业务逻辑分析

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

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

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

    • 异步随机生成各种各类型的客户,比例VIP:普通客户:快速客户:1:6:3。

    • 客户办理业务所需时间有最大值和最小值,普通客户和VIP客户办理业务所需时间再两者之间,快速客户取最小值。

    • 当VIP窗口和快速窗口没有客户等待办理业务时,这两个窗口可以处理普通客户的业务。

        该题目的业务逻辑和交通灯管理系统有很多相似之处,都是基于多线程并发执行的业务逻辑,至少需要2个线程,业务窗口线程:负责即时检测有没有对应的客户在排队,VIP窗口和快速窗口在没有对应客户排队的情况下,可以处理普通客户的业务。生成客户线程:每个一定的时间就产生一个不同类型的客户。在现实的银行营业厅中都有一个排好机,选择业务类型就会打印出一个排队号码,这里我们也模拟设计一个排号机,负责客户排队。

    二、系统详细设计

    根据业务需求分析,设计这样几个对象:服务窗口对象,客户对象,排号机对象。下面具体分析每个对象所以属性和方法。

    服务窗口对象:应该有窗口类型和窗口编号两个属性。提供3个方法,用于检测3种类型的客户是否又在排队的。

    客户对象:这里系统主要是银行的业务逻辑,客户不需要具体化,用一个数字或字符串表示就行了。但是需要一个客户类型对象来表示不同的客户,这里用枚举类型实现。

    排号机对象:对办理业务的客户排号的前提是先有客户,所以排号机兼负产生模拟客户的人物,产生一个客户也就是有一个客户进入对应类型的排队排列。

    主要类图如下:

    具体实现和业务逻辑分析略有不同,但整体设计是相同的。

    三、具体实现

    NumberManager.java

    public class NumberManager {
    	private int lastNumber = 0;
    	//客戶排队队列
    	private List<Integer> queueNumbers = new ArrayList<Integer>();
    	//随机产生模拟客户
    	public synchronized Integer generateNewNumber(){
    		queueNumbers.add(++lastNumber);
    		return lastNumber;
    	}
    	//服务窗口获取下一个客户
    	public synchronized Integer fetchNumber(){
    		if(queueNumbers.size()>0){
    			return (Integer)queueNumbers.remove(0);
    		}else{
    			return null;
    		}
    	}
    }

    ServiceWindow.java

    public class ServiceWindow {
    	// 根据客户类型获取下一个客户
    	private CustomerType type = null;
    	// 服务窗口编号
    	private int windowId = 1;
    
    	public ServiceWindow(CustomerType type, int windowId) {
    		super();
    		this.type = type;
    		this.windowId = windowId;
    	}
    
    	public void start() {
    		Executors.newSingleThreadExecutor().execute(new Runnable() {
    
    			@Override
    			public void run() {
    				do{
    					switch (type) {
    					case COMMON:
    						commonService();
    						break;
    					case VIP:
    						expressService();
    						break;
    					case EXPRESS:
    						vipService();
    						break;
    						
    					default:
    						break;
    					}
    				}while(true);
    			}
    
    		});
    	}
    
    	private void commonService() {
    		String windowName = windowId + "号普通窗口";
    		// 尝试从客户排队队列中获取下一个客户
    		System.out.println(windowName + " 正在获取任务。。。");
    		Integer serviceNum = NumberMachine.getInstance().getCommonManager()
    				.fetchNumber();
    		if (serviceNum != null) {
    			// 用sleep模拟客户服务时间
    			System.out.println(windowName + "开始为" + serviceNum + "号普通客户服务");
    			int max_Random = Constants.MAX_SERVICE_TIME
    					- Constants.MIN_SERVICE_TIME;
    			long serviceTime = new Random().nextInt(max_Random) + 1+Constants.MIN_SERVICE_TIME;
    			try {
    				Thread.sleep(serviceTime);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println(windowName + "为 " + serviceNum
    					+ " 号普通客户服务完成,用时:" + serviceTime / 1000 + " 秒");
    		} else {
    			System.out.println(windowName + " 没有获取到客户,等待中。。。");
    			try {// 等待1秒
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}

    CustomerType.java

    public enum CustomerType {
    	VIP,EXPRESS,COMMON;
    	public String toString(){
    		switch (this) {
    		case VIP:
    			return "VIP";
    		case EXPRESS:
    			return "快速";
    		case COMMON:
    			return "普通";
    		}
    		return null;
    	}
    }

    NumberMachine.java

    public class NumberMachine {
    	
    	private static NumberMachine instance = new NumberMachine();
    	//普通客戶排号机
    	private NumberManager commonManager = new NumberManager();
    	//快速客戶排号机
    	private NumberManager expressManager = new NumberManager();
    	//VIP客戶排号机
    	private NumberManager vipManager = new NumberManager();
    	//单例模式创建一个号码管理器
    	private NumberMachine(){}
    	
    	public static NumberMachine getInstance(){
    		return instance;
    	}
    	public NumberManager getCommonManager() {
    		return commonManager;
    	}
    	public NumberManager getExpressManager() {
    		return expressManager;
    	}
    	public NumberManager getVipManager() {
    		return vipManager;
    	}	
    }

  • 相关阅读:
    bootstrap-15
    sqlserver 根据指定值截取字符串
    idea针对有外联jar包的项目如何编译成可运行的jar包
    中控考勤机超级管理员密码算法
    sql server 取多条数据的最大值
    bat 脚本定时删除备份文件
    Spyder汉化教程
    君荣一卡通软件mysql转sqlserver 教程
    office2016专业增强版激活密匙 (shell激活版)
    sql 获取当前时间的前一天,不加时分秒
  • 原文地址:https://www.cnblogs.com/lukeguo/p/8824777.html
Copyright © 2020-2023  润新知