这个例子来自java编程思想,模拟了银行出纳的多线程场景
package com.igoso.learning;
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;
/**
* created by igoso at 2017/12/20
* 模仿银行出纳的多线程服务场景,java编程思想
**/
public class BankTellerSimulation {
static final int MAX_LINE_SIZE = 50;
static final int ADJUSTMENT_PERIOD = 1000;
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
//if customer line is too line , customer will leave
CustomerLine customers = new CustomerLine(MAX_LINE_SIZE);
exec.execute(new CustomerGenerator(customers));
//manager add and remove tellers as necessary
exec.execute(new TellerManager(exec,customers,ADJUSTMENT_PERIOD));
// exec.shutdownNow();
}
}
class Customer{
private final int serviceTime;
public Customer(int tm){
serviceTime = tm;
}
public int getServiceTime() {
return serviceTime;
}
@Override
public String toString() {
return "[" + serviceTime + "]";
}
}
class CustomerLine extends ArrayBlockingQueue<Customer>{
public CustomerLine(int capacity) {
super(capacity);
}
@Override
public String toString() {
if(this.size()==0){
return "[empty]";
}
StringBuilder sb = new StringBuilder();
for(Customer customer: this){
sb.append(customer);
}
return sb.toString();
}
}
class CustomerGenerator implements Runnable{
private CustomerLine customers;
private static Random random = new Random(47);
public CustomerGenerator(CustomerLine customerLine) {
this.customers = customerLine;
}
public void run() {
try {
while (!Thread.interrupted()){
TimeUnit.MILLISECONDS.sleep(random.nextInt(300));
customers.put(new Customer(random.nextInt(8000)));
}
}catch (InterruptedException e){
System.out.println("Customer generator interrupted");
}
System.out.println("Customer generator terminating");
}
}
class Teller implements Runnable , Comparable<Teller>{
private static int counter = 0;
private final int id = counter++;
private int customerServed = 0;
private CustomerLine customers;
private boolean servingCustomerLine = true;
public Teller(CustomerLine customers){
this.customers = customers;
}
public synchronized int compareTo(Teller o) {
return customerServed < o.customerServed?-1:(customerServed == o.customerServed?0:1);
}
public void run() {
try {
while (!Thread.interrupted()) {
Customer customer = customers.take();
TimeUnit.MILLISECONDS.sleep(customer.getServiceTime());
synchronized (this) {
customerServed++;
while (!servingCustomerLine) {
wait();
}
}
}
} catch (InterruptedException e) {
System.out.println(this + "interrupted");
}
System.out.println(this + "terminating");
}
public synchronized void doSomethingElse() {
customerServed=0;
servingCustomerLine=false;
}
public synchronized void serveCustomerLine(){
assert !servingCustomerLine:"already serving:"+ this;
servingCustomerLine=true;
notifyAll();
}
@Override
public String toString() {
return "Teller " + id + " ";
}
public String shortString() {
return "T" + id;
}
}
class TellerManager implements Runnable{
private ExecutorService exec;
private CustomerLine customers;
private PriorityQueue<Teller> workingTellers= new PriorityQueue<Teller>();
private Queue<Teller> tellerDoingOtherThings = new LinkedList<Teller>();
private int adjustmentPeriod;
private static Random random = new Random(47);
public TellerManager(ExecutorService exec, CustomerLine customers, int adjustmentPeriod){
this.exec = exec;
this.customers = customers;
this.adjustmentPeriod = adjustmentPeriod;
//start with a new single teller
Teller teller = new Teller(customers);
exec.execute(teller);
workingTellers.add(teller);
}
//空闲分配任务
public void adjustTellerNumber(){
if(customers.size()/ workingTellers.size()>2){
//if tellers are on break or doing
// another job, bring one back
if(tellerDoingOtherThings.size()>0){
Teller teller = tellerDoingOtherThings.remove();
teller.serveCustomerLine();
workingTellers.offer(teller);
return;
}
//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(customers.size() == 0){
while (workingTellers.size()>1){
reassignOneTeller();
}
}
}
private void reassignOneTeller(){
Teller teller = workingTellers.poll();
teller.doSomethingElse();
tellerDoingOtherThings.offer(teller);
}
public void run() {
try {
while (!Thread.interrupted()){
TimeUnit.MILLISECONDS.sleep(adjustmentPeriod);
adjustTellerNumber();
System.out.print(customers + "{");
for(Teller teller : workingTellers){
System.out.print(teller.shortString() + " ");
}
System.out.println("}");
}
}catch (InterruptedException e){
System.out.println(this + " interrupted");
}
System.out.println(this + "terminating");
}
}