【ThinkingInJava】64、银行出纳员仿真
/** * 书本:《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)
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。