package concurrent;

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 tm) {
serviceTime = tm;
} public int getServiceTime() {
return serviceTime;
} public String toString() {
return "[" + serviceTime + "]";
}
} class CustomerLine extends ArrayBlockingQueue<Customer> {
public CustomerLine(int maxLineSize) {
super(maxLineSize);
} public String toString() {
if (this.size() == 0)
return "[Empty]"; StringBuilder result = new StringBuilder();
for (Customer customer : this) {
result.append(customer);
}
return result.toString();
}
} class CustomerGenerator implements Runnable {
private CustomerLine customers;
private static Random rand = new Random(47); public CustomerGenerator(CustomerLine cq) {
customers = cq;
} public void run() {
try {
while (!Thread.interrupted()) {
TimeUnit.MILLISECONDS.sleep(rand.nextInt(300));
customers.put(new Customer(rand.nextInt(1000)));
// System.out.println(customers.toString());
}
} catch (InterruptedException e) {
System.out.println("CustomerGenerator interrupted");
}
System.out.println("CustomerGenerator terminating");
}
} 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");// 结束
} public synchronized void doSomethingElse() {
customersServed = 0;
servingCustomerLine = false;
} public synchronized void serveCustomerLine() {
assert !servingCustomerLine : "already serving:" + this;
servingCustomerLine = true;
notifyAll();
} public String toString() {
return "Teller " + id + " ";
} public String shortString() {
return "T" + id;
} public synchronized int compareTo(Teller other) {
return customersServed < other.customersServed ? -1
: (customersServed == other.customersServed ? 0 : 1);
}
} 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);
} /**
* 调整出纳员数量
* */
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();
} /**
* 分配一个出纳员
* */
private void reassignOneTeller() {
Teller teller = workingTellers.poll();
teller.doSomethingElse();
tellersDoingOtherThings.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");
} public String toString() {
return "TellerManager";
}
} 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();
}
}

Java多线程之银行出纳员仿真的更多相关文章

  1. Thinking in Java---多线程仿真:银行出纳员仿真+饭店仿真+汽车装配工厂仿真

    多线程一个非常有意思的作用就是用于仿真,这篇博客就会结合几个仿真实例来综合运用一下前面所学的多线程并发知识. 一.银行出纳员仿真 问题描写叙述:银行会有非常多来办业务的顾客,他们会排队等待服务:对于银 ...

  2. java多线程(精华版)

    在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应 ...

  3. Java多线程编程——进阶篇二

    一.线程的交互 a.线程交互的基础知识 线程交互知识点需要从java.lang.Object的类的三个方法来学习:    void notify()           唤醒在此对象监视器上等待的单个 ...

  4. Java 多线程 锁 存款 取款

    http://jameswxx.iteye.com/blog/806968 最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣.已经拟好了提纲,大概分为这几个主题: ja ...

  5. 【转】Java多线程学习

    来源:http://www.cnblogs.com/samzeng/p/3546084.html Java多线程学习总结--线程概述及创建线程的方式(1) 在Java开发中,多线程是很常用的,用得好的 ...

  6. Java多线程详解

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  7. java多线程(五)-访问共享资源以及加锁机制(synchronized,lock,voliate)

    对于单线程的顺序编程而言,每次只做一件事情,其享有的资源不会产生什么冲突,但是对于多线程编程,这就是一个重要问题了,比如打印机的打印工作,如果两个线程都同时进行打印工作,那这就会产生混乱了.再比如说, ...

  8. Java多线程之线程的同步

    Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...

  9. Java 多线程 死锁 隐性死锁 数据竞争 恶性数据竞争 错误解决深入分析 全方向举例

    在几乎所有编程语言中,由于多线程引发的错误都有着难以再现的特点,程序的死锁或其它多线程错误可能只在某些特殊的情形下才出现,或在不同的VM上运行同一个程序时错误表现不同.因此,在编写多线程程序时,事先认 ...

随机推荐

  1. CentOS 6 DEPRECATED

    Created by YEISON CAMARGO, last modified by John Boteler on 2016.02.02 Go to start of metadata   Abo ...

  2. 在CentOS里使用MySQL Connector/C++

    操作系统版本:CentOS6 64位 1,安装boost库.因为MySQL Connector/C++使用了boost库,所以必须先安装boost库,我们才能使用MySQL Connector/C++ ...

  3. OSGi 的由来和本质特性

    OSGi 的由来 随着科技和需求的发展和变化,现在的软件变得越来越庞大.这样,随之而来的最大挑战就是软件在设计上的越来越复杂和维护上的越来越困难.为了解决这个问题,软件架构师将软件切分成比较小的并且易 ...

  4. PCA人脸识别

    人脸数据来自http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html 实现代码和效果如下.由于图片数量有限(40*10),将原 ...

  5. premiere视频输出参数设置

  6. Heap Only Tuples (HOT)

    Introduction ------------ The Heap Only Tuple (HOT) feature eliminates redundant index entries and a ...

  7. PHP使用Mysql事务

    <?php //数据库连接 $conn = mysql_connect('localhost', 'root', ''); mysql_select_db('test', $conn); mys ...

  8. 怎么用ABBYY打开PDF文档

    我们日常工作中接触的文档大多都是PDF格式的,这种格式的文件需要借助工具才能打开,大家最熟悉的无非就是Adobe了,但你知道吗?除了Adobe,OCR文字识别软件也可以打开PDF文档,比如ABBYY ...

  9. oracle进程

    http://blog.csdn.net/leshami/article/details/5529239 Oracle实例和Oracle数据库(Oracle体系结构) 几类进程:用户进程,服务进程,后 ...

  10. web首页设置如下代码可判断用户是用什么设备登录的?

    var OnePage=true;//用来判断staticHtml.js中首页登入的信息判断var _mobileUrl = "http://a.abc.com";//手机用户通过 ...