java多线程:银行窗口业务

本人面试遇到的多线程笔试题,主要考察的多线程编程和面向对象思想。主要关注:多个窗口办理业务,有VIP窗口和普通窗口。VIP窗口可以办理普通业务,普通业务窗口只能办理普通业务,VIP用户在VIP窗口可以优先办理。一般核心业务实现出来就可以了。

题目

1、银行内有6个业务窗口,1-4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口;
2、有三种对应类型的客户:VIP客户,普通客户,快速客户
3、异步随机生成各种类型客户,生成各类型用户的概率比例为:VIP客户:快速客户:普通客户 = 1:3:6
4、客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值
5、各类型客户在其对应窗口按顺序依次办理业务;
6、VIP窗口和快速窗口优先处理对应客户的业务,这两个窗口也可以处理普通客户的业务。

分析

  • 对象:窗口、银行顾客、取号机
  • 窗口类型:普通窗口、VIP窗口、快速窗口。
  • 业务类型:普通业务、VIP业务、快速业务。
  • 多线程:每一个窗口为一个线程,顾客生成一个线程。
    关系类图

代码

顾客实体

public class Consumer {
    //取号号码
    public Integer id;
    //类型:普通、快速、VIP
    public ConsumerType consumerType;

    public Consumer(Integer id, ConsumerType consumerType) {
        this.id = id;
        this.consumerType = consumerType;
    }
     //省略set、get
     
    /**
     * 模拟业务执行时间
     */
    public void execute() {
        Random random = new Random();
        try {
            switch (consumerType) {
                case NORMAL:
                    TimeUnit.SECONDS.sleep(random.nextInt(10) + 1);
                    break;
                case QUICK:
                    TimeUnit.SECONDS.sleep(1);
                    break;
                case VIP:
                    TimeUnit.SECONDS.sleep(random.nextInt(10) + 1);
                    break;
            }
        } catch (Exception exception) {
            exception.printStackTrace();
            System.out.println("业务异常");
        }
    }
}
//顾客枚举类
public enum ConsumerType {
    NORMAL, QUICK, VIP;

    @Override
    public String toString() {
        String name = null;
        switch (this) {
            case NORMAL:
                name = "普通";
                break;
            case QUICK:
                name = "快速";
                break;
            case VIP:
                name = name();
                break;
        }
        return name;
    }
}

取号机(用户和号码管理器)
使用线程安全的阻塞队列BlockingQueue和原子类AtomicInteger实现用户取号排队。

public class ConsumerManager {

    /**
     * 用户号码(原子类线程安全)
     */
    public AtomicInteger norNumber = new AtomicInteger(1);
    public AtomicInteger vipNumber = new AtomicInteger(1);
    public AtomicInteger quickNumber = new AtomicInteger(1);

    /**
     * 用户队列(线程安全)
     */
    public ArrayBlockingQueue<Consumer> norQueue = new ArrayBlockingQueue<>(10);
    public ArrayBlockingQueue<Consumer> vipQueue = new ArrayBlockingQueue<>(10);
    public ArrayBlockingQueue<Consumer> quickQueue = new ArrayBlockingQueue<>(10);

    /**
     * 按照概率(VIP:快速:普通=1:3:6)产生用户
     */
    public void produce() {
        Random random = new Random();
        try {
            while (true) {
                // put阻塞添加客户
                int type = random.nextInt(10);
                if (type < 1) {
                    System.out.println("产生第" + vipNumber.get() + "号vip顾客");
                    vipQueue.put(new Consumer(vipNumber.getAndIncrement(), ConsumerType.VIP));
                } else if (type < 4) {
                    System.out.println("产生第" + quickNumber.get() + "号快速顾客");
                    quickQueue.put(new Consumer(quickNumber.getAndIncrement(), ConsumerType.QUICK));
                } else {
                    System.out.println("产生第" + norNumber.get() + "号普通顾客");
                    norQueue.put(new Consumer(norNumber.getAndIncrement(), ConsumerType.NORMAL));
                }
                // 根据情况停顿一秒,方便观察
                TimeUnit.SECONDS.sleep(1);
            }

        } catch (Exception e) {
        	e.printStackTrace();
        }

    }

    public ArrayBlockingQueue<Consumer> getNorQueue() {
        return norQueue;
    }

    public void setNorQueue(ArrayBlockingQueue<Consumer> norQueue) {
        this.norQueue = norQueue;
    }

    public ArrayBlockingQueue<Consumer> getVipQueue() {
        return vipQueue;
    }

    public void setVipQueue(ArrayBlockingQueue<Consumer> vipQueue) {
        this.vipQueue = vipQueue;
    }

    public ArrayBlockingQueue<Consumer> getQuickQueue() {
        return quickQueue;
    }

    public void setQuickQueue(ArrayBlockingQueue<Consumer> quickQueue) {
        this.quickQueue = quickQueue;
    }
}

窗口类
分别定义三个不同的窗口,抽象公共特性。每个窗口都持有ConsumerManager (取号机)的实例,获取对应顾客办理业务。

public abstract class Window {
	/**
	 * 窗口号
	 */
	public Integer windowId;
	/**
	 * 窗口类型
	 */
	public String windowType;

	public Window(Integer windowId, String windowType) {
		this.windowId = windowId;
		this.windowType = windowType;
	}
	/**
	 * 公共服务方法
	 */
	public abstract void service(ConsumerManager consumerManager);
}

/**
 * 普通窗口
 */
public class NormalWindow extends Window {

    public NormalWindow(int i) {
        super(i, "普通");
    }

    @Override
    public void service(ConsumerManager consumerManager) {
        while (true) {
            try {
                ArrayBlockingQueue<Consumer> norQueue = consumerManager.getNorQueue();
                // TODO 普通窗口一直阻塞获取用户
                System.out.println(windowId + "号" + windowType + "窗口空闲中~~~~");
                Consumer consumer = norQueue.take();
                System.out.println(windowId + "号" + windowType + "窗口业开始办理第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
                consumer.execute();
                System.out.println(windowId + "号" + windowType + "窗口办理完了第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 快速窗口
 */
public class QuickWindow extends Window {

    public QuickWindow(int i) {
        super(i, "快速");
    }

    @Override
    public void service(ConsumerManager consumerManager) {
        while (true) { // 优先快速业务
            ArrayBlockingQueue<Consumer> quiQueue = consumerManager.getQuickQueue();
            Consumer consumer = quiQueue.poll();
            if (consumer != null) {
                System.out.println(windowId + "号" + windowType + "窗口开始办理第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
                consumer.execute();
                System.out.println(windowId + "号" + windowType + "窗口办理完了第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
            } else { // 普通业务
                ArrayBlockingQueue<Consumer> norQueue = consumerManager.getNorQueue();
                consumer = norQueue.poll();
                if (consumer != null) {
                    System.out.println(windowId + "号" + windowType + "窗口业开始办理第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
                    consumer.execute();
                    System.out.println(windowId + "号" + windowType + "窗口办理完了第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
                }

            }

        }
    }

}

/**
 * VIP窗口
 */
public class VIPWindow extends Window {

    public VIPWindow(int i) {
        super(i, "VIP");
    }

    @Override
    public void service(ConsumerManager consumerManager) {
        while (true) { // 优先VIP业务
            ArrayBlockingQueue<Consumer> vipQueue = consumerManager.getVipQueue();
            Consumer consumer = vipQueue.poll();
            if (consumer != null) {
                System.out.println(windowId + "号" + windowType + "窗口开始办理第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
                consumer.execute();
                System.out.println(windowId + "号" + windowType + "窗口办理完了第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
            } else { // 普通业务
                ArrayBlockingQueue<Consumer> norQueue = consumerManager.getNorQueue();
                consumer = norQueue.poll();
                if (consumer != null) {
                    System.out.println(windowId + "号" + windowType + "窗口业开始办理第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
                    consumer.execute();
                    System.out.println(windowId + "号" + windowType + "窗口办理完了第" + consumer.getId() + "号" + consumer.getConsumerType().toString() + "顾客的业务");
                }
            }

        }
    }
}

测试

线程池启动线程,分别创建4个普通窗口、一个快速窗口、一个VIP窗口,并用不同线程启动。另外启动一个顾客生成线程。(推荐手动创建线程池,不要使用jdk自带的Executors工具类)直接运行main方法。

public class MainTest {
	public static void main(String[] args) throws InterruptedException {
		final ConsumerManager consumerManager = new ConsumerManager();
		final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(7, 7, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
		//final ExecutorService threadPool = Executors.newFixedThreadPool(7);
		threadPool.execute(() -> {
			// 持续按概率产生顾客
			consumerManager.produce();
		});
		// 产生4个普通窗口
		for (int i = 1; i < 5; i++) {
			Window normalWindow = new NormalWindow(i);
			threadPool.execute(() -> {
				normalWindow.service(consumerManager);
			});
		}
		// 5号快速窗口
		Window quickWindow = new QuickWindow(5);
		threadPool.execute(() -> {
			quickWindow.service(consumerManager);
		});
		// 6号VIP窗口
		Window vipWindow = new VIPWindow(6);
		threadPool.execute(() -> {
			vipWindow.service(consumerManager);
		});

	}
}

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值