package learn.thread;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 顾客
* <br>
* 每个Teller任务在任何时刻都只从输入队列中移除一个Customer
* 并且在这个Customer上工作直至完成 因此Customer 在任何时刻
* 都只由一个任务访问
* @author 陈中强
* @Time 2017年7月10日 上午11:40:00
*/
class Customer{
/**
* final 修饰 对象不会发生变化 只读对象
* 并且不需要同步或者使用volatile
*/
private final int serviceTime;
public Customer(int tm){
serviceTime = tm;
}
public int getServiceTime(){
return serviceTime;
}
public String toString(){
return "[Customer:"+serviceTime+"]";
}
}
/**
* 顾客排队 先进先出 队列
* @author 陈中强
* @Time 2017年7月10日 下午4:16:55
*/
class CustomerLine extends ArrayBlockingQueue<Customer>{
public CustomerLine(int maxLineSzie) {
super(maxLineSzie);
}
public String toString(){
if(this.size() == 0){
return "Customer Empty";
}
StringBuilder result = new StringBuilder();
for(Customer customer : this){
result.append(customer);
}
return result.toString();
}
}
/**
* 客户队列生成
* @author 陈中强
* @Time 2017年7月10日 下午4:17:49
*/
class CustomerGenerator implements Runnable{
private CustomerLine customers;
private static Random rand = new Random(47);
public CustomerGenerator(CustomerLine cq){
customers = cq;
}
@Override
public void 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");
}
}
/**
* 柜员
* @author 陈中强
* @Time 2017年7月10日 下午4:19:03
*/
class Teller implements Runnable,Comparable<Teller>{
private static int counter = 0;
private final int id = counter++;
private int customersServed = 0;//已经服务的客户 customers served during this shift
private CustomerLine customers;//客户队列
private boolean servingCustomerLine = true;//是否正在服务客户
public Teller(CustomerLine cq){
customers = cq;
}
@Override
public void run() {
try{
while(!Thread.interrupted()){
Customer customer = customers.take();
TimeUnit.MILLISECONDS.sleep(customer.getServiceTime());
synchronized(this){
customersServed++;
while(!servingCustomerLine){
wait();
}
}
}
}catch(InterruptedException e){
System.out.println(this + " interrupted");
}
System.out.println(this +" terminating");
}
/**
* 做其他事 不服务客户了
* @author 陈中强-chen
* @Time 2017年7月10日 下午4:24:13
*/
public synchronized void dosomethingElse(){
customersServed = 0;
servingCustomerLine = false;
}
/**
* 断言 正在服务客户时
* 并唤醒所有线程
* @author 陈中强-chen
* @Time 2017年7月10日 下午2:11:06
*/
public synchronized void serveCustomerLine(){
assert !servingCustomerLine : "already serving:" + this;
servingCustomerLine = true;
notifyAll();
}
public String toString(){
return "Teller "+ id +" ";
}
public String shortString(){
return "T"+id;
}
/**
* 比较 已经服务的客户 customersServed
* @param other
* @return
* @see java.lang.Comparable#compareTo(java.lang.Object)
* @author 陈中强-chen
* @Time 2017年7月10日 下午2:17:55
*/
@Override
public synchronized int compareTo(Teller other) {
return customersServed < other.customersServed ? -1
:(customersServed == other.customersServed ? 0 :1);
}
}
/**
* 柜员管理
* @author 陈中强
* @Time 2017年7月10日 下午4:28:10
*/
class TellerManager implements Runnable{
private ExecutorService exec;
private CustomerLine customers;
//优先级队列 头部指向 排序的最小元素
private PriorityQueue<Teller> workingTellers = new PriorityQueue<Teller>();
private Queue<Teller> tellersDoingOtherThings = new LinkedList<Teller>();
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);
workingTellers.add(teller);
}
/**
* 调整出纳员数量
* This is actually a control system . By adjusting the number.
* you can reveal stability issues in the control mechanism.
* If line too long .add anther teller.
* @author 陈中强-chen
* @Time 2017年7月10日 下午2:58:23
*/
public void adjustTellerNumber(){
//如果客户的数量是柜员的两倍多
if(customers.size()/ workingTellers.size() > 2){
//如果有做其他事情的柜员 If tellers are on break or doing another job .bring one back:
if(tellersDoingOtherThings.size() > 0){
//从做其他事的 柜员中 调出第一个
Teller teller = tellersDoingOtherThings.remove();
//去服务客户
teller.serveCustomerLine();
//工作中的队列就加了一个人
workingTellers.offer(teller);
return;
}
// Else create(hire) a new teller
Teller teller = new Teller(customers);
exec.execute(teller);
workingTellers.add(teller);
return;
}
// If line is short enough.remove a teller
if(workingTellers.size() >1 && customers.size() / workingTellers.size() < 2){
reassignOneTeller();
}
// If there is no line . we only need one teller .
if(customers.size() == 0){
while(workingTellers.size() > 1){
reassignOneTeller();
}
}
}
/**
* 分配出一个出纳员
* Give a teller a different job or a break:
* @author 陈中强-chen
* @Time 2017年7月10日 下午3:09:15
*/
private void reassignOneTeller() {
Teller teller = workingTellers.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 : workingTellers){
System.out.println(teller.shortString() + " ");
}
System.out.println("}");
}
} catch (InterruptedException e) {
System.out.println(this + " interrupted");
}
System.out.println(this + " terminating");
}
public String toString(){
return "TellerManager";
}
}
/**
* 银行出纳员仿真 主函数
* @author 陈中强
* @Time 2017年7月10日 下午5:05:30
*/
public class BankTellerSimulation {
static final int MAX_LINE_SIZE = 50;
static final int ADJUSTMENT_PERIOD = 1000;
public static void main(String[] args) throws Exception{
ExecutorService exec = Executors.newCachedThreadPool();
//If line too long .customers will leave;
CustomerLine customers = new CustomerLine(MAX_LINE_SIZE);
exec.execute(new CustomerGenerator(customers));
// Manager will add and remove tellers as necessary:
exec.execute(new TellerManager(exec, customers, ADJUSTMENT_PERIOD));
if(args.length > 0){// Option argument
TimeUnit.SECONDS.sleep(new Integer(args[0]));
}else{
System.out.println("Press "
+ "'Enter' to quit");
System.in.read();
}
exec.shutdownNow();
}
}
银行出纳员仿真
最新推荐文章于 2022-04-07 13:06:58 发布