zoukankan      html  css  js  c++  java
  • java 之 面试题银行业务调度

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

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

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

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

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

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

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

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

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

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

    看了需求,就按着自己的想法开始做:

    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.Enumeration;
    import java.util.LinkedList;
    import java.util.Random;
    import java.util.Vector;
    import java.util.concurrent.TimeUnit;
    
    public class Test {
    	DateFormat date;
    
    	// 这个是限制概率,存放的是某个类型的客户
    	// 内部类不允许使用静态变量,只好放这里了
    	static int defaultCount = 0;
    	static int fastCount = 0;
    	static int VIPCount = 0;
    
    	public Test() {
    		date = new SimpleDateFormat("HH:mm:ss");
    	}
    
    	// 客户类,代表各种客户
    	public class Customer {
    
    		private String name;
    		// 客户类型 2,1,3分表代表,快速,vip,普通客户
    		private int type;
    		private LinkedList<Customer> window;
    
    		public void setWindow(LinkedList<Customer> window) {
    			this.window = window;
    		}
    
    		public LinkedList<Customer> getWindow() {
    			return window;
    		}
    
    		// 办理业务所需时间,秒
    		private int time;
    
    		public int getType() {
    			return type;
    		}
    
    		public int getTime() {
    			return time;
    		}
    
    		public void setName(String name) {
    			this.name = name;
    		}
    
    		public String getName() {
    			return name;
    		}
    
    		public Customer(int type) {
    			this.type = type;
    
    			Random r = new Random();
    
    			// 2是快速客户,1是vip客户,3是普通客户,这三个数是基数
    			// 随机一个办理业务的时间,根据客户类型算出所需时间,
    			// 原则的时间大小顺序是普通>VIP>快速客户
    			time = (this.type % 2 + this.type) * r.nextInt(4) + 5;
    		}
    
    	}
    
    	// 窗口类,代表了各个窗口等待容器
    	public class Window implements CustLinstener {
    		// 各个窗口容器
    		private LinkedList<Customer> VIP6;
    		private LinkedList<Customer> fast5;
    		// 这是个普通窗口容器
    		private ArrayList<LinkedList<Customer>> defaults124;
    		private LinkedList<Customer> default1;
    		private LinkedList<Customer> default2;
    		private LinkedList<Customer> default3;
    		private LinkedList<Customer> default4;
    
    		public LinkedList<Customer> getVIP6() {
    			return VIP6;
    		}
    
    		public LinkedList<Customer> getFast5() {
    			return fast5;
    		}
    
    		public LinkedList<Customer> getDefault1() {
    			return default1;
    		}
    
    		public LinkedList<Customer> getDefault2() {
    			return default2;
    		}
    
    		public LinkedList<Customer> getDefault3() {
    			return default3;
    		}
    
    		public LinkedList<Customer> getDefault4() {
    			return default4;
    		}
    
    		public Window() {
    			// 初始化各个窗口
    			default1 = new LinkedList<Customer>();
    			default2 = new LinkedList<Customer>();
    			default3 = new LinkedList<Customer>();
    			default4 = new LinkedList<Customer>();
    			defaults124 = new ArrayList<LinkedList<Customer>>();
    			defaults124.add(default1);
    			defaults124.add(default2);
    			defaults124.add(default3);
    			defaults124.add(default4);
    			fast5 = new LinkedList<Customer>();
    			VIP6 = new LinkedList<Customer>();
    		}
    
    		// 增加一个客户
    		public void addCustomer(Customer cu) {
    			if (cu.getType() == 2) {
    				cu.setWindow(fast5);
    				fast5.add(cu);
    				System.out.println(date.format(new Date()) + "	--["
    						+ cu.getName() + "]号客户被加到了[快速窗口]队列并等待办理[快速业务]");
    			} else if (cu.getType() == 1) {
    				cu.setWindow(VIP6);
    				VIP6.add(cu);
    				System.out.println(date.format(new Date()) + "	--["
    						+ cu.getName() + "]号客户被加到了[VIP窗口]队列并等待办理[VIP业务]");
    			} else {
    
    				// 普通用户的话,按原则先推到人少的窗口
    				int size = 0;
    				for (int i = 1; i < 4; i++) {
    					if (defaults124.get(i).size() < defaults124.get(size)
    							.size())
    						size = i;
    				}
    				defaults124.get(size).add(cu);
    				System.out.println(date.format(new Date()) + "	--["
    						+ cu.getName() + "]号客户被加到了[普通窗口]队列并等待办理[普通业务]");
    
    			}
    		}
    
    		// 客户业务办理完毕,删除一个客户
    		public void removeCustomer(LinkedList<Customer> window) {
    			// 如果是快速窗口的业务,并且快速窗口没有人了,就从普通窗口调剂过去
    			if (window == fast5 && fast5.size() == 0) {
    				// 首先判断所有普通窗口是不是都有人
    				boolean usingAll = true;
    				for (LinkedList<Customer> w : defaults124) {
    					if (w.size() == 0)
    						usingAll = false;
    				}
    
    				// 都是用了的话,就调剂
    				if (usingAll) {
    					// 首先取得是哪个普通窗口人最多
    					int size = 0;
    					// 前提条件是他们都有客户
    
    					for (int i = 1; i < 5; i++) {
    						if (defaults124.get(i).size() > defaults124.get(size)
    								.size())
    							size = i;
    					}
    					// 将人数最多的窗口的下一个接受业务办理的客户已送到快速窗口
    					Customer temp = defaults124.get(size).get(1);
    					defaults124.get(size).remove(1);
    
    					fast5.addLast(temp);
    
    				} else {
    					Customer c = window.peek();
    					System.out.println(date.format(new Date()) + "  ["
    							+ c.getName() + "]号客户走人");
    					window.poll();
    
    				}
    			} else {
    				Customer c = window.peek();
    				System.out.println(date.format(new Date()) + "  ["
    						+ c.getName() + "]号客户走人");
    				window.poll();
    			}
    
    		}
    
    		@Override
    		public void custEvent(CustEvent e) {
    			// TODO Auto-generated method stub
    			Customer cu = new Customer(e.getType());
    			cu.setName(e.getName());
    			addCustomer(cu);
    
    		}
    
    	}
    
    	// 业务员,就那几个个窗口的业务员
    	public class Officer {
    		private Window windows;
    		private LinkedList<Customer> default1;
    		private LinkedList<Customer> default2;
    		private LinkedList<Customer> default3;
    		private LinkedList<Customer> default4;
    		private LinkedList<Customer> fast5;
    		private LinkedList<Customer> vip6;
    
    		public Officer(Window w) {
    			windows = w;
    			default1 = w.getDefault1();
    			default2 = w.getDefault2();
    			default3 = w.getDefault3();
    			default4 = w.getDefault4();
    			fast5 = w.getFast5();
    			vip6 = w.getVIP6();
    		}
    
    		// 六个业务员开始工作
    		public void startWork() {
    
    			// 1号业务员工作
    			Thread t1 = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					// TODO Auto-generated method stub
    					try {
    						while (!Thread.interrupted()) {
    							if (default1.size() > 1) {
    								doing(default1, "普通窗口①");
    							}
    						}
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    
    				}
    			});
    
    			// 2号业务员工作
    			Thread t2 = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					// TODO Auto-generated method stub
    					try {
    						while (!Thread.interrupted()) {
    							if (default2.size() > 1) {
    								doing(default2, "普通窗口②");
    
    							}
    						}
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    
    				}
    			});
    
    			// 3号业务员工作
    			Thread t3 = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					// TODO Auto-generated method stub
    					try {
    						while (!Thread.interrupted()) {
    							if (default3.size() > 1) {
    								doing(default3, "普通窗口③");
    
    							}
    						}
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    
    				}
    			});
    
    			// 4号业务员工作
    			Thread t4 = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					// TODO Auto-generated method stub
    					try {
    						while (!Thread.interrupted()) {
    							if (default4.size() > 1) {
    								doing(default4, "普通窗口④");
    
    							}
    						}
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    
    				}
    			});
    
    			// 5号快速窗口业务员工作
    			Thread t5 = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					// TODO Auto-generated method stub
    					try {
    						while (!Thread.interrupted()) {
    							if (fast5.size() > 1) {
    								doing(fast5, "快速窗口⑤");
    
    							}
    						}
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    
    				}
    			});
    
    			// 6号VIP窗口业务员工作
    			Thread t6 = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					// TODO Auto-generated method stub
    					try {
    						while (!Thread.interrupted()) {
    							if (vip6.size() > 1) {
    								doing(vip6, "VIP窗口⑥");
    
    							}
    						}
    					} catch (InterruptedException e) {
    						// TODO Auto-generated catch block
    						e.printStackTrace();
    					}
    
    				}
    			});
    
    			t1.setPriority(Thread.NORM_PRIORITY);
    			t2.setPriority(Thread.NORM_PRIORITY);
    			t3.setPriority(Thread.NORM_PRIORITY);
    			t4.setPriority(Thread.NORM_PRIORITY);
    			t5.setPriority(Thread.NORM_PRIORITY);
    			t6.setPriority(Thread.NORM_PRIORITY);
    
    			t1.start();
    			t2.start();
    			t3.start();
    			t4.start();
    			t5.start();
    			t6.start();
    
    		}
    
    		private void doing(LinkedList<Customer> window, String wn)
    				throws InterruptedException {
    			Customer c = window.peek();
    			System.out.println(date.format(new Date()) + "  [" + c.getName()
    					+ "]号客户在[" + wn + "]办理业务,预计时间[" + c.getTime() + "]秒");
    			Thread.yield();
    			TimeUnit.SECONDS.sleep(c.getTime());
    			windows.removeCustomer(window);
    		}
    
    	}
    
    	// 这个类随机产生客户
    	public class GodKing implements Runnable {
    		// 事件
    		CustAdaper ca;
    
    		// 标示客户
    		private Integer number;
    		// 随机数种子
    		private Random random;
    
    		// 窗口
    		// private Window windows;
    
    		public GodKing(Window w) {
    			number = 100;
    			random = new Random();
    			// windows=w;
    			ca = new CustAdaper();
    
    		}
    
    		// 开始生成客户
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			try {
    				Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
    				while (!Thread.interrupted()) {
    
    					// 这里来实现VIP客户 :普通客户 :快速客户 = 1 :6 :3的比例
    					int dtype = random.nextInt(3) + 1;
    
    					// 快速业务客户与普通客户没有达到指定比例,但vip达到了,就避免类型为vip
    					if (VIPCount == 1 && fastCount < 3 && defaultCount < 6) {
    						do {
    							dtype = random.nextInt(3) + 1;
    						} while (dtype == 1);
    						// 快速客户与vip客户已经是指定比例,普通的还不是
    					} else if (VIPCount == 1 && fastCount == 3
    							&& defaultCount < 6) {
    						do {
    							dtype = random.nextInt(3) + 1;
    						} while (dtype == 1 || dtype == 2);
    					} else {
    						// 已经是指定比例了计数器归零
    						VIPCount = 0;
    						fastCount = 0;
    						defaultCount = 0;
    					}
    
    					switch (dtype) {
    					case 1:
    						VIPCount++;
    					case 2:
    						fastCount++;
    					case 3:
    						defaultCount++;
    					}
    					// Customer c=new Customer(dtype);
    					// c.setName(number.toString());
    					// windows.addCustomer(c);
    					number++;
    					CustEvent e = new CustEvent();
    					e.setName(number.toString());
    					e.setType(dtype);
    					ca.notifyCustEvent(e);
    					// 最多10秒钟来一个人
    					Thread.yield();
    					TimeUnit.SECONDS.sleep(random.nextInt(10));
    
    				}
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    
    		public void addCustEventListener(CustLinstener cu) {
    			ca.addCustListener(cu);
    		}
    
    	}
    
    	public static void main(String[] args) {
    		Test t = new Test();
    		Window windows = t.new Window();
    		Officer officers = t.new Officer(windows);
    		GodKing god = t.new GodKing(windows);
    		god.addCustEventListener(windows);
    
    		officers.startWork();
    		god.run();
    
    	}
    
    	// 新客户事件
    	public class CustEvent {
    		private int type;
    		private String name;
    
    		public int getType() {
    			return type;
    		}
    
    		public void setType(int type) {
    			this.type = type;
    		}
    
    		public String getName() {
    			return name;
    		}
    
    		public void setName(String name) {
    			this.name = name;
    		}
    	}
    
    	public interface CustLinstener {
    		public void custEvent(CustEvent e);
    	}
    
    	public class CustAdaper {
    		private Vector<CustLinstener> events = new Vector<CustLinstener>();
    		CustLinstener cu;
    
    		public void addCustListener(CustLinstener wc) {
    			events.addElement(wc);
    		}
    
    		public void notifyCustEvent(CustEvent e) {
    			Enumeration<CustLinstener> listener = events.elements();
    			while (listener.hasMoreElements()) {
    				cu = listener.nextElement();
    				cu.custEvent(e);
    			}
    		}
    	}
    
    }
    

    这几百行的,居然让Js着色解析时栈溢出,ie6不行啊。。。

    对于一个自己学习测试用的东西,喜欢写成单类单文件,这样方便复制粘贴直接编译,内部类比较多。

    写完后,发现在前5个到前6个模拟客户,业务实现逻辑总是工作不正常,整整花了半天多时间研究为神马,起初是没打算用事件的,但后来考虑到的问题,想想加上事件机制会不会解决,结果呢还是没有解决,开发模式却变得不伦不类,把线程优先级别改改呢,最高的模式下,居然电脑死机了。

    再想想,是不是线程过多了,改成了单独两个线程,还是有点问题,最后再仔细看看《thinking in java》,并发确实是个很难说的东西,再加上时间片本来分配的问题,那几个线程怎么可能确保同步呢。。。。

    最后,看了下张老师的代码,。。。。。居然和我的路子不一样,我想的过于细了。结果给自己造了这么多绊子。就先这样吧,改天再深入研究研究并发。

  • 相关阅读:
    Jakarta雅加达项目简介
    java的Commons包简介
    装饰者模式
    命令模式
    桥接模式
    适配器模式
    观察者模式
    模板模式
    责任链模式
    CentOS搭建NAT和DHCP服务,实现共享上网
  • 原文地址:https://www.cnblogs.com/hangxin1940/p/2045390.html
Copyright © 2011-2022 走看看