package com.current.demo;
import java.io.IOException;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.*;
/**
- 程序描述:
-
随机生成多个客户
-
业务员管理器会根据客户的数量分配不同业务员的数量
-
当客户逐渐变少时,当前工作的业务员也会有一部分被回收掉(并不是真正意义的回收,而是保存在另一个队列里面)
-
然而,当客户又变多时,之前被回收的部分业务员会回来重新工作
- */
//Customer是个只是读的对象 (代表客户)
class Customer{
//要是这个客户服务的时长
private final int serverTime;
public Customer(int m){
System.out.println("create Customer finish serverTime="+m);
serverTime = m;
}
//获取时长
public int getServerTime(){
return serverTime;
}
//打印时长
public String toString(){
return "[" + serverTime + "]";
}
}
//表示所有等待的客户
class CustomerLine extends ArrayBlockingQueue{
//最大等待客户的数量
public CustomerLine(int maxLineSize){
super(maxLineSize);
}
//定制打印格式
public String toString(){
//如果等待客户为0 就打印empty
if(this.size() == 0){
return "[Empty]";
}
//字符串拼接对象
StringBuilder result = new StringBuilder();
//拼接名称
for(Customer customer : this){
result.append(customer);
}
return result.toString();
}
}
//随机的生成客户 (往等待列表中添加)
class CustomerGenerator implements Runnable{
//等待列表
private CustomerLine customers;
//随机数对象
private static Random rand = new Random(47);
public CustomerGenerator(CustomerLine cq){
System.out.println("create CustomerGenerator finshed");
customers = cq;
}
@Override
public void run(){
System.out.println("create CustomerGenerator is run");
try{
//不断的模拟新的客户
while(!Thread.interrupted()){
//随机睡眠 模拟新来一个客户 ------
TimeUnit.MILLISECONDS.sleep(rand.nextInt(300));
customers.put(new Customer(rand.nextInt(1000)));
//---------
}
}catch (InterruptedException e){
System.out.println("CustomerGenerator interrupted");
}
System.out.println("CustomerGenerator terminating");
}
}
//具体处理客户的出纳员
class Teller implements Runnable,Comparable{
//------------ 这两个字段用来表示出纳员的id(标识) -----
private static int counter = 0;
private final int id = counter++;
//----------------------------------
private int customersServed = 0; //服务的人数
//等待客户的列表 所有出纳员共享的服务列表
private CustomerLine customers;
private boolean servingCustomerLine = true;
//构造出纳员
public Teller(CustomerLine cq){
System.out.println("ctreate Teller finshed id="+id);
customers = cq;
}
//出纳员工作入口
@Override
public void run() {
try{
while(!Thread.interrupted()){
//从等待客户列表拿出等待的客户 并进行处理
Customer customer = customers.take();
TimeUnit.MILLISECONDS.sleep(customer.getServerTime());
//锁定当前对象
synchronized (this){
//当前出纳员处理的客户数量+1
customersServed++;
while(!servingCustomerLine){
wait();
}
}
}
}catch (InterruptedException e){
System.out.println(this + " interrupted");
}
System.out.println(this + " terminating");
}
//
public synchronized void doSomethingElse(){
customersServed = 0;
servingCustomerLine = false;
}
public synchronized void serveCustomerLine(){
//如果条件不成立就报错 程序终止
assert !servingCustomerLine : "already serving:" + this;
servingCustomerLine = true;
notifyAll();
}
public String toString(){
return "Teller " + id + " ";
}
public String shortString(){
return "T" + id;
}
public synchronized int compareTo(Teller other){
return customersServed < other.customersServed ? -1:
(customersServed == other.customersServed ? 0 : 1);
}
}
//活动中心
class TellerManager implements Runnable{
//线程工具
private ExecutorService exec;
//等待客户列表
private CustomerLine customers;
//具有优先级有界的队列 根据出纳员的业务量来进行排序
private PriorityQueue<Teller> workingTellerss = new PriorityQueue<Teller>();
//LinkeList implements Deque Deque implements Queue (才知道)
//当前没有工作的业务员
private Queue<Teller> tellersDoingOtherThings = new LinkedList<>();
//这个代表的是某一个界值吧(睡眠的时间)
private int adjustmentPeriod;
//生产随机数的对象
private static Random rand = new Random(47);
public TellerManager(ExecutorService e,CustomerLine customers,int adjustmentPeriod){
exec = e;
this.customers = customers;
this.adjustmentPeriod = adjustmentPeriod;
//刚开始的时候先初始化有一个业务员
Teller teller = new Teller(customers);
exec.execute(teller);
workingTellerss.add(teller);
}
public void adjustTellerNumber(){
//如果等待队列中的长度 / 业务员的数量 大于2
if(customers.size() / workingTellerss.size() > 2){
//如果这个业务员待处理的数量大于0
if(tellersDoingOtherThings.size() > 0){
//拿出一个
Teller teller = tellersDoingOtherThings.remove();
//标志为已经处理
teller.serveCustomerLine();
workingTellerss.add(teller);
return;
}
Teller teller = new Teller(customers);
exec.execute(teller);
workingTellerss.add(teller);
return;
}
if(workingTellerss.size() > 1 && customers.size() / workingTellerss.size() < 2){
reassignOneTeller();
}
if(customers.size() == 0){
while(workingTellerss.size() > 1){
reassignOneTeller();
}
}
}
private void reassignOneTeller(){
Teller teller = workingTellerss.poll();
teller.doSomethingElse();
tellersDoingOtherThings.offer(teller);
}
@Override
public void run() {
try{
while (!Thread.interrupted()){
//睡眠
TimeUnit.MILLISECONDS.sleep(adjustmentPeriod);
adjustTellerNumber();
System.out.println(customers + " { ");
//
for(Teller teller : workingTellerss){
System.out.print(teller.shortString() + ",");
}
System.out.println();
System.out.println("}");
}
}catch (InterruptedException e){
System.out.println(this + " interrupted");
}
System.out.println(this + " terminating");
}
public String toString(){
return "TellerManager";
}
}
class BankTellerSimulation {
static final int MAX_LIME_SIZE = 50;
static final int ADJUSTMENT_PERIOD = 1000;
public static void main(String[] args) throws IOException, InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
CustomerLine customers = new CustomerLine(MAX_LIME_SIZE);
exec.execute(new CustomerGenerator(customers));
exec.execute(new TellerManager(exec,customers,ADJUSTMENT_PERIOD));
if(args.length > 0){
TimeUnit.SECONDS.sleep(new Integer(args[0]));
}else{
System.out.println("Press 'Enter' to quit");
System.in.read();
}
exec.shutdown();
}
}