----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
1、业务分析:
模拟整个银行大厅的工作,需要在大脑中构建银行大厅的场景。主要是两个过程。1)、陆续随机进入三种类型(普通、快速服务、vip)的客户,他们去取票排队,取号机分类将他们内在的划分为了3个不同的队列(号码性质不同),每当一个用户去被服务了,那么就销毁这一个号码,每当进入一个客户,相应的增加一个号码。2)、窗口的工作人员不停的工作,他们会根据窗口的属性、根据服务对象的队列号去叫下一个人来办理业务。Vip窗口和快速窗口当本类的业务客户都处理完了,就去帮助普通窗口工作。
注意:三类客户的产生比例不同,1:3:6,用线程的周期时间来控制,没个周期内都产生一个相应类型的客户,那么把周期时间控制到1:3:6则就让用户数量呈现这个比例了。且不同的客户在办理业务时时间也是不同的,有一个范围限定,普通客户和vip客户在范围内随机,快速用户为最小办理时间,sleep模拟。
2、类规划:
NumberMachine:取号机,一个大厅只有一个取号机,所以单例实现。同时该取号机内存在三种号码管理器,分别对应三种客户的号码管理。同时使用线程提供三种号码管理器的业务工作,即产生用户。
NumberManage:虽然有三种用户,但是他们产生号码的号码管理器工作方式都是一样的,封装成一个类,在NumberMachine中创建3个对象即可;使用一个List属性存放用户编号。提供添加用户的方法。提供获取队列最首用户的方法给窗口业务员去调用。
ServiceWindow:提供一个ID属性和TYPE属性(类型显然是枚举),同时为该两种属性提供set方法,而不是在构造器中绑定ID和TYPE,更符合实际情况,因为窗口实际生活中可以改变属性的。该类还根据3种窗口类型分别3种业务处理方法,使用线程实现,不停叫号工作。
CustomerType:枚举类,为ServiceWindow的TYPE属性提供值。方便使用,重写toString方法,
Constants:常量类,存放系统中使用的常量。
BankSystem:系统工作类。
3、具体实现:
NumberManager.java
- package blog13Bank;
- import java.util.ArrayList;
- import java.util.List;
- // 号码管理器,用户号码产生的类
- public class NumberManager {
- private int lastNumber = 0;
- private List<Integer> queue = new ArrayList<>();
- public synchronized Integer newCustomer(){ /*设置成线程锁的方法,因为该方法用NumberMachine的对象调用
- 而叫号去办理用户的方法由ServiceWindow窗口类调用,不同类共同访问queue会线程安全问题,所以加锁*/
- queue.add(++lastNumber);
- return lastNumber;
- }
- public synchronized Integer fetchNumber(){
- if(queue.size()>0){
- return queue.remove(0); //取走队首元素,
- }
- return null;//队列为空,没有用户,就返回null4,所以方法返回值需要设置成Integer
- }
- }
NumberMachine.java
- package blog13Bank;
- // 取号机,是一个单例,先当普通类实现业务,再将类写成单例
- public class NumberMachine {
- private NumberManager commonManager = new NumberManager();
- private NumberManager expressManager = new NumberManager();
- private NumberManager vipManager = new NumberManager();
- //创建三个号码管理器,并提供get获取方法
- public NumberManager getCommonManager() {
- return commonManager;
- }
- public NumberManager getExpressManager() {
- return expressManager;
- }
- public NumberManager getVipManager() {
- return vipManager;
- }
- //写成单例
- private NumberMachine(){}
- private static NumberMachine instance = new NumberMachine();
- public static NumberMachine getInstance(){
- return instance;
- }
- //取号机的业务可以用线程写在构造器中,意味着一创造出来就不停工作了,也可以在其他类中使用到取号机再写业务
- //本例放到BankSystem类中开始工作时为取号机指定业务:使用定时器固定频率工作,造成用户比例1:3:6
- }
ServiceWindow.java
- package blog13Bank;
- import java.util.Random;
- import java.util.concurrent.Executors;
- //银行的窗口类
- //我自己的思路:写一个模板父类window:提供protected属性和一个抽象的work方法,然后三种窗口为其三种子类,重写其work方法即可
- public class ServiceWindow {
- private int ID = 1; //默认为1号窗口
- private WindowType type = WindowType.COMMON;//默认为普通窗口
- //提供属性设置方法,用于创建不同类型的窗口
- public void setID(int iD) {
- ID = iD;
- }
- public void setType(WindowType type) {
- this.type = type;
- }
- //工作业务,线程编写,使其不停的叫号工作。
- public void work(){
- Executors.newSingleThreadExecutor().execute(new Runnable(){
- @Override
- public void run() {
- switch(type){//根据窗口类型不同,有不同的业务处理方式
- case COMMON:
- while(true){
- commonService();
- }
- case EXPRESS:
- while(true){
- expressService();
- }
- case VIP:
- while(true){
- vipService();
- }
- }
- }});
- }
- //业务流程:窗口叫号
- public void commonService(){
- String name = type/*调用枚举的toString*/ + ":第 " + ID + " 号窗口";
- Integer number = NumberMachine.getInstance().getCommonManager().fetchNumber();
- System.out.println(name + "开始获取 普通任务");//这个任务种类实际就和number种类也就是NmuberManager对象绑定
- if(number!=null){//叫号成功,模拟工作,模拟随机工作时间
- System.out.println(name + "获取 普通任务 成功,"+ name + "正在为第 " + number + " 号 普通客户 服务");
- int runTime = new Random().nextInt(Constants.RANDOM_FOR_WORK)+1+Constants.MIN_WORK_TIME;
- try {
- Thread.sleep(runTime);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(name + "为第 " + number + " 号 普通用户 完成服务,共耗时 " + runTime/1000 + " 秒");
- }else{//叫号失败,没有客户了
- System.out.println(name + "没有取到 普通任务,空闲一秒...");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public void expressService(){
- String name = type/*调用枚举的toString*/ + ":第 " + ID + " 号窗口";
- Integer number = NumberMachine.getInstance().getExpressManager().fetchNumber();
- System.out.println(name + "开始获取 快速任务");//这个任务种类实际就和number种类也就是NmuberManager对象绑定
- if(number!=null){//叫号成功,模拟工作,模拟随机工作时间
- System.out.println(name + "获取 快速任务 成功,"+ name + "正在为第 " + number + " 号 快速客户 服务");
- int runTime = Constants.MIN_WORK_TIME;
- try {
- Thread.sleep(runTime);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(name + "为第 " + number + " 号 快速用户 完成服务,共耗时 " + runTime/1000 + " 秒");
- }else{//叫号失败,没有客户了
- System.out.println(name + "没有取到 快速任务...");
- commonService();
- }
- }
- public void vipService(){
- String name = type/*调用枚举的toString*/ + ":第 " + ID + " 号窗口";
- Integer number = NumberMachine.getInstance().getVipManager().fetchNumber();
- System.out.println(name + "开始获取 VIP任务");//这个任务种类实际就和number种类也就是NmuberManager对象绑定
- if(number!=null){//叫号成功,模拟工作,模拟随机工作时间
- System.out.println(name + "获取 VIP任务 成功,"+ name + "正在为第 " + number + " 号 VIP客户 服务");
- int runTime = new Random().nextInt(Constants.RANDOM_FOR_WORK)+1+Constants.MIN_WORK_TIME;
- try {
- Thread.sleep(runTime);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(name + "为第 " + number + " 号 VIP用户 完成服务,共耗时 " + runTime/1000 + " 秒");
- }else{//叫号失败,没有客户了
- System.out.println(name + "没有取到 VIP任务...");
- commonService();
- }
- }
- }
WindowType.java
- package blog13Bank;
- public enum WindowType {
- COMMON,EXPRESS,VIP;
- @Override
- public String toString() {
- String name = null;
- switch(this){
- case COMMON:
- name = "普通";
- break;
- case EXPRESS:
- name = "快速";
- break;
- case VIP:
- name = this.name();
- break;
- }
- return name;
- }
- }
Constants.java
- package blog13Bank;
- public class Constants {
- public static int MIN_WORK_TIME = 1000; //最小业务办理时限1000毫秒
- public static int MAX_WORK_TIME = 10000;//最大业务办理时间10000毫秒
- public static int RANDOM_FOR_WORK = 10000-1000;//业务时间范围
- }
BankSystem.java
- package blog13Bank;
- import java.util.concurrent.Executors;
- import java.util.concurrent.TimeUnit;
- public class BankSystem {
- public static void main(String[] args) {
- //创建6个窗口
- for(int i=1;i<=4;i++){
- ServiceWindow window = new ServiceWindow();
- window.setID(i);
- window.work();
- }
- ServiceWindow window = new ServiceWindow();
- window.setType(WindowType.EXPRESS);
- window.work();
- window = new ServiceWindow();
- window.setType(WindowType.VIP);
- window.work();
- //创建NumberMachine对象,因为是单例,不用创对象了,并为之编写业务代码
- //三个线程产生3种用户
- Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
- new Runnable(){
- @Override
- public void run() {
- Integer number = NumberMachine.getInstance().
- getCommonManager().newCustomer();
- System.out.println("第 " + number + " 位普通用户进入大厅,等待服务...");
- }
- },
- 0,
- 1,
- TimeUnit.SECONDS);
- Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
- new Runnable(){
- @Override
- public void run() {
- Integer number = NumberMachine.getInstance().
- getExpressManager().newCustomer();
- System.out.println("第 " + number + " 位快速用户进入大厅,等待服务...");
- }
- },
- 0,
- 3/*快速用户周期为3秒*/,
- TimeUnit.SECONDS);
- Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
- new Runnable(){
- @Override
- public void run() {
- Integer number = NumberMachine.getInstance().
- getVipManager().newCustomer();
- System.out.println("第 " + number + " 位VIP用户进入大厅,等待服务...");
- }
- },
- 0,
- 6/*vip用户周期为6秒*/,
- TimeUnit.SECONDS);
- }
- }