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;
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(tellersDoingOtherThings.size() >
0){
Teller teller = tellersDoingOtherThings.remove();
teller.serveCustomerLine();
workingTellers.offer(teller);
return;
}
Teller teller =
new Teller(customers);
exec.execute(teller);
workingTellers.add(teller);
return;
}
if(workingTellers.size() >
1 && customers.size() / workingTellers.size() <
2){
reassignOneTeller();
}
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();
CustomerLine customers =
new CustomerLine(MAX_LINE_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.shutdownNow();
}
}