模拟银行某一时段的服务流程 ---- IBM面试题

注:本博客内容没有通过面试,呵呵...请不要盲信博客内容!!!

这段时间一直在找工作,说实话现在行情真不是太好,叫我去面试的大都是外包公司,而我又不很喜欢做外包,所以很郁闷,也挺焦急...这是背景。

今天下午又接到一外包公司的面试电话,是外包到IBM的,不知什么原因没有推掉,于是负责招聘的MM发来一道IBM的试题,说是做完让那边看完之后才能安排面试。于是乎,忙活了好大一会子,终于将其解决。

由于以前没做银行项目,对于并发这块也不是很熟悉,所以解决方式很别扭,也不知道是否对题目理解正确,现将解决方案发表于此,请大家指正。


试题信息


要求

请在一个小时内完成。

问题描述

请模拟银行某一时段的服务流程

银行有4个服务窗口,其中有三个是普通窗口,一个是VIP窗口。VIP窗口在没有VIP用户时也可以当作普通服务窗口办理业务。银行的服务流程描述如下:

  • 首先到达的客户需要在门口领取一张号码纸,号码纸上写明了前面排队的人数和你的号码。
  • 客户等待自己被服务。如果号码纸的的号码过期,即当前的号码大于号码纸的号码,则号码纸就过期了
  • 如果VIP用户到达后,VIP用户进入VIP窗口办理,如果VIP窗口前面有其他的VIP用户,则排在其他VIP用户之后,如果有普通会员在办理,则服务完成后立刻服务VIP用户。
  • 银行的业务员在服务完一个客户后,会根据号码纸依次通知下一个客户进行服务
用户的数据放在一个文本文件中

类似于如下所示(各列依次为:次序、客户类型、到达时间、服务时间):

1 普通 09:00 5
2 普通 09:00 6
3 普通 09:00 5
4 普通 09:02 9
5 普通 09:04 5
6 VIP 09:05 7
7 普通 09:10 5
8 普通 09:12 10
9 普通 09:15 5
10 VIP 09:18 5
11 普通 09:18 8
12 普通 09:19 5

输出

请输出每一个窗口的服务客户列表,以及每一个客户的等待时间


解决方案


首先定义客户类,客户类型以枚举表示,个人觉得题目不算复杂,因此并没有好好设计,没有将客户类抽象出父类,而是VIP客户和普通客户都由此类表示:

package com.ibm.bank;

import java.util.Date;

/**
 * 客户类, 例子比较简单, 没有再提取父类, VIP和普通客户都用此类代表, 以customType区分.
 * @author zyh
 */
public class Custom implements Comparable<Custom>{
	private Long order;				// 客户次序
	private CustomType customType;	// 客户类型
	private Date arrivalDate;		// 到达时间
	private int serviceTime;		// 服务时长

	public long getOrder() {
		return order;
	}

	public void setOrder(long order) {
		this.order = order;
	}

	public CustomType getCustomType() {
		return customType;
	}

	public void setCustomType(CustomType customType) {
		this.customType = customType;
	}

	public Date getArrivalDate() {
		return arrivalDate;
	}

	public void setArrivalDate(Date arrivalDate) {
		this.arrivalDate = arrivalDate;
	}

	public int getServiceTime() {
		return serviceTime;
	}

	public void setServiceTime(int serviceTime) {
		this.serviceTime = serviceTime;
	}

	@Override
	public int compareTo(Custom o) {
		return this.order.compareTo(o.order);
	}
}

/**
 * 客户类型枚举类
 * @author zyh
 */
enum CustomType {
	VIP("the VIP custom."),
	COMMON("the COMMON custom.");
	
	private String description;
	
	private CustomType(String desc) {
		this.description = desc;
	}
	
	public String getDescription() {
		return this.description;
	}
	
	@Override
	public String toString() {
		return this.description;
	}
}

接着给出两个窗口类(VIP窗口和普通窗口),业务窗口类实现了Runnable接口,表示这是一个任务;在窗口中循环从客户端获取下一个客户(VIP窗口获取下一个VIP客户,如果接下来没有VIP客户了,则获取普通客户),如果客户存在则打印服务列表,然后休眠客户服务时长,如果接下来再没有客户了,则该窗口关闭(线程结束)。

VIP窗口:

package com.ibm.bank;

import java.util.concurrent.TimeUnit;

/**
 * VIP窗口, 办理VIP用户业务, 如果没有VIP用户在等待, 也可以办理普通用户业务.
 * @author zyh
 */
public class VIPWindow implements Runnable {
	private Client client;
	
	public VIPWindow(Client client) {
		this.client = client;
	}

	@Override
	public void run() {
		Custom cs = null;
		while ((cs = client.nextCustom(CustomType.VIP)) != null) {
			long waitedTime = System.currentTimeMillis() - client.getServiceStartTime();
			try {
				System.out.println("VIP Window is Servicing for Custom " + cs.getOrder()
						+ ", Custom Type: " + cs.getCustomType().name() + ", arrival time: "
						+ String.format("%1$tF %1$tR", cs.getArrivalDate()) + ", waited time: "
						+ waitedTime/1000 + "S");
				// 服务时间
				TimeUnit.MINUTES.sleep(cs.getServiceTime());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

普通窗口:

package com.ibm.bank;

import java.util.concurrent.TimeUnit;

/**
 * 普通用户窗口
 * @author zyh
 */
public class GeneralWindow implements Runnable {
	private String windowName;
	private Client client;
	
	public GeneralWindow(Client client, String winName) {
		this.client = client;
		this.windowName = winName;
	}
	
	public void run() {
		Custom cs = null;
		while((cs = client.nextCustom(CustomType.COMMON)) != null) {
			long waitedTime = System.currentTimeMillis() - client.getServiceStartTime();
			try {
				System.out.println("General Window(" + this.windowName + ") is Servicing for Custom "
						+ cs.getOrder() + ", Custom Type: " + cs.getCustomType().name() + ", arrival time: "
						+ String.format("%1$tF %1$tR", cs.getArrivalDate()) + ", waited time: "
						+ waitedTime/1000 + "S");
				TimeUnit.MINUTES.sleep(cs.getServiceTime());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

	public String getWindowName() {
		return windowName;
	}

	public void setWindowName(String windowName) {
		this.windowName = windowName;
	}
}

最后是客户端代码,用一个LinkedList类存储解析得到的所有客户(可将其作为队列使用),然后在static代码块中解析客户信息文件并填充LinkedList,最后在main方法中创建了三个普通窗口线程和一个VIP窗口线程,丢进执行器ExecutorService 中:

package com.ibm.bank;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Client {
	private static LinkedList<Custom> customList = new LinkedList<Custom>();
	private Long serviceStartTime;
	
	public Long getServiceStartTime() {
		return serviceStartTime;
	}

	public Client() {
		serviceStartTime = System.currentTimeMillis();
	}
	
	static {
		InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/ibm/bank/customs.txt");
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		try {
			String line = reader.readLine();
			String regex = "^\\d{1,2} [\\u4E00-\\u9FFF|\\w]{2,3} \\d{2}:\\d{2} \\d{1,}$";
			Calendar calendar = Calendar.getInstance();
			while(null != line && line.matches(regex)) {
				String [] customInfo = line.split(" ");
				Custom custom = new Custom();
				custom.setOrder(Long.parseLong(customInfo[0]));
				custom.setServiceTime(Integer.parseInt(customInfo[3]));
				if (customInfo[1].equals("VIP")) {
					custom.setCustomType(CustomType.VIP);
				} else {
					custom.setCustomType(CustomType.COMMON);
				}
				String [] time = customInfo[2].split(":");
				calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(time[0]));
				calendar.set(Calendar.MINUTE, Integer.parseInt(time[1]));
				custom.setArrivalDate(calendar.getTime());
				
				customList.offer(custom);
				
				line = reader.readLine();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != reader) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static void main(String[] args) {
		Client client = new Client();
		
		ExecutorService executorService = Executors.newCachedThreadPool();
		executorService.execute(new GeneralWindow(client, "第1普通窗口"));
		executorService.execute(new GeneralWindow(client, "第2普通窗口"));
		executorService.execute(new GeneralWindow(client, "第3普通窗口"));
		executorService.execute(new VIPWindow(client));
		
		executorService.shutdown();
	}

	/**
	 * 获取下一个客户
	 * @param customType 客户类型
	 * @return VIP窗口或者普通窗口要服务的下一个客户
	 */
	public synchronized Custom nextCustom(CustomType customType) {
		if (customType == CustomType.VIP) {
			Custom cs; int index = 0;
			while (index < customList.size() && (cs = customList.get(index++)) != null) {
				if (customType == cs.getCustomType()) {
					customList.remove(cs);
					return cs;
				}
			}
		}
		return customList.poll();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值