/**
* 书本:《Thinking In Java》
* 功能:对象随机地出现,并且要求由数量有限的服务器提供随机数量的服务时间。
* 每个银行顾客要求一定数量的服务时间,这是出纳员必须花费在顾客身上,以服务顾客需求的时间单位的数量。服务时间的数量对每个顾客来说都是不同的,并且是随机确定的。
* 另外,你不知道在每个时间间隔内有多少顾客会到达,因此这也是随机确定的:
* 文件:BankTellerSimulation.java
* 时间:2015年5月10日08:36:06
* 作者:cutter_point
*/
package Lesson21Concurency;
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;
//客户类
class Customer
{
private final int serviceTime; //客户要求被服务的时间
public Customer(int serviceTime)
{
this.serviceTime = serviceTime;
}
public int getServiceTime()
{
return serviceTime;
}
@Override
public String toString()
{
return "顾客要求的 [服务时间 =" + serviceTime + "]";
}
}
//顾客队列
/*
* 一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素。队列的尾部 是在队列中存在时间最短的元素。
* 新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。
这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。
试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。
*/
class CustomerLine extends ArrayBlockingQueue<Customer>
{
public CustomerLine(int maxLineSize) //数组的最大长度
{
super(maxLineSize);
}
@Override
public String toString()
{
if(this.size() == 0)
return "[没有顾客,为空]";
StringBuilder result = new StringBuilder();
for(Customer customer : this)
{
//吧数组里面的顾客全部取出来,放到string里面去
result.append(customer);
}
return result.toString();
}
}
//顾客产生器,随机产生顾客
class CustomerGenerator implements Runnable
{
//得到顾客的队列
private CustomerLine customers;
//产生随机数
Random rand = new Random(998);
public CustomerGenerator(CustomerLine customers)
{
this.customers = customers;
}
@Override
public void run()
{
try
{
//只要当前线程没有被打断,那么我们就不断地产生新的顾客
while(!Thread.interrupted())
{
//为了随机时间里面产生顾客,产生的顾客需求也是随机地
//随机一段时间 nextInt是产生一个在0到指定的数据之间的数
TimeUnit.MILLISECONDS.sleep(rand.nextInt(300));
//然后队列里面添加一个随机地顾客
customers.put(new Customer(rand.nextInt(1000)));
}
}
catch (InterruptedException e)
{
System.out.println("顾客产生器线程被打断了");
e.printStackTrace();
}
System.out.println("顾客产生器 终结(terminating)");
}
}
//银行出纳员类
class Teller implements Runnable, Comparable<Teller>
{
private static int count = 0; //计数,银行有几个出纳员
private final int id = count++; //当前出纳员的员工id号
private int customersServed = 0; //当前出纳员服务了多少顾客
private CustomerLine customers; //顾客队列
private boolean servingCustomerLine = true; //当前是否有顾客队列
public Teller(CustomerLine customers)
{
this.customers = customers;
}
//当没有顾客的时候,做点其他的事
public synchronized void doSomethingElse()
{
//吧服务过的顾客数修正为0
customersServed = 0;
//并把当前的服务队列改为没有队列
servingCustomerLine = false;
}
//当出现许多顾客的时候,该上班做事了
public synchronized void serveCustomerLine()
{
//来个断言assertion机制,判定已经服务了多少人
assert !servingCustomerLine : " 已经服务了: " + this; //判定!servingCustomerLine是不是为false,如果不是那就用第二个String作为产生,抛出异常
servingCustomerLine = true; //重新把队列启动
//唤醒其他说有的工作
this.notifyAll();
}
//选择当前类服务过的顾客最小的出纳员进行工作
@Override
public synchronized int compareTo(Teller o)
{
return customersServed < o.customersServed ? -1 : (customersServed == o.customersServed ? 0 : 1);
}
@Override
public void run()
{
try
{
//首先这个线程没有被中断
while(!Thread.interrupted())
{
//然后队列里面排第一个的顾客脱离队伍,接受服务
Customer customer = customers.take();
//这个要被服务的时间队列需要停顿
TimeUnit.MILLISECONDS.sleep(customer.getServiceTime());
//然后给这个出纳员的服务数量添加一个
synchronized(this)
{
customersServed++;
while(!servingCustomerLine) //当队列没有人的时候
this.wait();
}
}
}
catch (InterruptedException e)
{
System.out.println(this + "被中断");
e.printStackTrace();
}
}
@Override
public String toString()
{
return "出纳员工号是 : [id=" + id + "]";
}
public String shortString() { return "员工号 : " + id; }
}
//银行管理类
class TellerManager implements Runnable
{
private ExecutorService exec; //线程连接池
private CustomerLine customers; //顾客队列
//一个基于优先级堆的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,
private PriorityQueue<Teller> workingTellers = new PriorityQueue<Teller>();
private Queue<Teller> tellerDoingOtherThings = new LinkedList<Teller>(); //没有加入工作的出纳员
private Random rand = new Random(998);
private int adjustmentPeriod; //调整期间
public TellerManager(ExecutorService exec, CustomerLine customers, int adjustmentPeriod)
{
this.exec = exec;
this.customers = customers;
this.adjustmentPeriod = adjustmentPeriod;
//首先银行最开始是一个出纳员工作,开始分配任务
Teller teller = new Teller(customers);
//投入工作
exec.execute(teller);
//工作的人加一个人
workingTellers.add(teller);
}
//这个函数用来调整工作的出纳员的人数,以及是否需要招聘
public void adjustTellerNumber()
{
//如果顾客队列比出纳员的人数的两倍还要多,注意是队列,所以我们得加一些出纳员进行工作了
if(customers.size() / workingTellers.size() > 2)
{
//首先,我们得确定公司里面还有一些人没有做事,在休息
if(tellerDoingOtherThings.size() > 0)
{
//吧那些没有上班的人全部拉上来去做事
Teller teller = tellerDoingOtherThings.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)
{
this.reassignOneTeller(); //休假去
}
//当完全没有顾客的时候
if(customers.size() == 0)
{
this.reassignOneTeller(); //休假去
}
}
private void reassignOneTeller()
{
Teller teller = workingTellers.poll(); //去掉头部元素
teller.doSomethingElse(); //休息去吧
tellerDoingOtherThings.offer(teller); //休假人数+1
}
@Override
public void run()
{
try
{
//当银行没有倒闭的时候
while(!Thread.interrupted())
{
TimeUnit.MILLISECONDS.sleep(adjustmentPeriod); //调整一段时间先
this.adjustTellerNumber(); //调整员工
System.out.println(customers + " { "); //顾客队列
for(Teller teller : workingTellers)
System.out.println(teller.shortString() + " "); //为队列工作
System.out.println(" } ");
}
}
catch (InterruptedException e)
{
System.out.println("好样的!银行倒闭了");
e.printStackTrace();
}
System.out.println("银行业务 终结(terminating)");
}
public String toString() { return "这是一家银行"; }
}
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));
for(int i = 0; i < 5; ++i)
{
System.out.println("回车,让银行破产!!!!!!!!");
}
System.in.read();
exec.shutdownNow(); //停止一切线程
}
}
回车,让银行破产!!!!!!!!
回车,让银行破产!!!!!!!!
回车,让银行破产!!!!!!!!
回车,让银行破产!!!!!!!!
回车,让银行破产!!!!!!!!
顾客要求的 [服务时间 =91]顾客要求的 [服务时间 =385]顾客要求的 [服务时间 =437]顾客要求的 [服务时间 =191]顾客要求的 [服务时间 =572] {
员工号 : 1
员工号 : 0
}
顾客要求的 [服务时间 =572]顾客要求的 [服务时间 =324]顾客要求的 [服务时间 =150]顾客要求的 [服务时间 =793]顾客要求的 [服务时间 =452]顾客要求的 [服务时间 =853]顾客要求的 [服务时间 =849]顾客要求的 [服务时间 =743]顾客要求的 [服务时间 =334] {
员工号 : 2
员工号 : 0
员工号 : 1
}
顾客要求的 [服务时间 =743]顾客要求的 [服务时间 =334]顾客要求的 [服务时间 =517]顾客要求的 [服务时间 =608]顾客要求的 [服务时间 =5]顾客要求的 [服务时间 =943]顾客要求的 [服务时间 =701]顾客要求的 [服务时间 =187]顾客要求的 [服务时间 =880] {
员工号 : 3
员工号 : 2
员工号 : 1
员工号 : 0
}
顾客要求的 [服务时间 =880]顾客要求的 [服务时间 =757]顾客要求的 [服务时间 =992]顾客要求的 [服务时间 =431]顾客要求的 [服务时间 =923]顾客要求的 [服务时间 =273]顾客要求的 [服务时间 =716] {
员工号 : 2
员工号 : 0
员工号 : 1
}
顾客要求的 [服务时间 =273]顾客要求的 [服务时间 =716]顾客要求的 [服务时间 =305]顾客要求的 [服务时间 =110]顾客要求的 [服务时间 =926]顾客要求的 [服务时间 =783]顾客要求的 [服务时间 =585]顾客要求的 [服务时间 =655] {
员工号 : 2
员工号 : 0
员工号 : 1
}
顾客要求的 [服务时间 =585]顾客要求的 [服务时间 =655]顾客要求的 [服务时间 =809]顾客要求的 [服务时间 =835]顾客要求的 [服务时间 =314]顾客要求的 [服务时间 =10] {
员工号 : 2
员工号 : 0
员工号 : 1
}
顾客要求的 [服务时间 =314]顾客要求的 [服务时间 =10]顾客要求的 [服务时间 =769]顾客要求的 [服务时间 =372]顾客要求的 [服务时间 =614]顾客要求的 [服务时间 =402]顾客要求的 [服务时间 =589]顾客要求的 [服务时间 =38]顾客要求的 [服务时间 =283] {
员工号 : 3
员工号 : 2
员工号 : 1
员工号 : 0
}
顾客要求的 [服务时间 =38]顾客要求的 [服务时间 =283]顾客要求的 [服务时间 =176]顾客要求的 [服务时间 =283]顾客要求的 [服务时间 =553]顾客要求的 [服务时间 =330]顾客要求的 [服务时间 =416]顾客要求的 [服务时间 =21]顾客要求的 [服务时间 =799]顾客要求的 [服务时间 =796]顾客要求的 [服务时间 =89] {
员工号 : 3
员工号 : 2
员工号 : 1
员工号 : 0
}
顾客要求的 [服务时间 =357]顾客要求的 [服务时间 =483]顾客要求的 [服务时间 =358]顾客要求的 [服务时间 =136]顾客要求的 [服务时间 =435] {
员工号 : 2
员工号 : 0
员工号 : 1
}
顾客产生器线程被打断了
好样的!银行倒闭了
出纳员工号是 : [id=2]被中断
出纳员工号是 : [id=3]被中断
出纳员工号是 : [id=1]被中断
出纳员工号是 : [id=0]被中断
java.lang.InterruptedException: sleep interrupted
顾客产生器 终结(terminating)
银行业务 终结(terminating)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:360)
at Lesson21Concurency.Teller.run(BankTellerSimulation.java:157)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:360)
at Lesson21Concurency.Teller.run(BankTellerSimulation.java:157)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:360)
at Lesson21Concurency.CustomerGenerator.run(BankTellerSimulation.java:92)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:360)
at Lesson21Concurency.TellerManager.run(BankTellerSimulation.java:257)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:360)
at Lesson21Concurency.Teller.run(BankTellerSimulation.java:157)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:360)
at Lesson21Concurency.Teller.run(BankTellerSimulation.java:157)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
原文地址:http://blog.csdn.net/cutter_point/article/details/45932201