这段时间在看Java并发编程方面的东西,注意到“生产者-消费者”模式,去某公司笔试的时候也遇到了这样的题,今天顺便把他用程序的方式写了下来。
UML就免了,不想画!顺便吐槽一下,小组开发,一定得用UML吗?随便画点图不行么?)
先上ServiceManager,它相当于大厅里的排号机,客户自己去排号,然后柜台的服务人员会去自动的取号:
/**
*
*/
package com.fcm.thread.banksample;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
/**
* @author fenggcai
*
*/
public class ServiceManager {
/**
* @param args
*/
public static void main(String[] args) {
//only 50 customers could be served a time
final BlockingQueue<FIFOEntry<Customer>> customerQueue = new PriorityBlockingQueue<FIFOEntry<Customer>>(
50);
for (int i = 0; i < 52; i++) {
int randomLevel = new Double(Math.random() * 5).intValue();
Customer c = new Customer("Customer" + i,
CustomerLevel.values()[randomLevel]);
new Thread(new CustomerService(customerQueue, c)).start();
}
for (int i = 0; i < 5; i++) {
BankService bs = new BankService(customerQueue);
new Thread(bs).start();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
接下来是客户自助排号CustomerService,这里做了一个简单的优先级CustomerLevel:
package com.fcm.thread.banksample;
import java.util.concurrent.BlockingQueue;
public class CustomerService implements Runnable {
private final BlockingQueue<FIFOEntry<Customer>> customerQueue;
private final Customer rootCustomer;
public CustomerService(BlockingQueue<FIFOEntry<Customer>> customerQueue,
Customer rootCustomer) {
super();
this.customerQueue = customerQueue;
this.rootCustomer = rootCustomer;
}
@Override
public void run() {
try {
addCustomer(rootCustomer);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void addCustomer(Customer customer) throws InterruptedException {
if (!customerQueue.contains(customer)) {
try {
customerQueue.add(new FIFOEntry<Customer>(customer));
} catch (IllegalStateException e) {
System.out.println("The queue is full!!");
throw new InterruptedException("Reach capacity limit.");
}
}
}
}
package com.fcm.thread.banksample;
public enum CustomerLevel {
BELOW_NORMAL,NORMAL,VIP,GOLD_VIP,URGUNT;
}
对于customer本身,因为前文提到了优先级的问题,所以为了排序的需要,这里我加入了对Comparable接口的支持:
package com.fcm.thread.banksample;
public class Customer implements Comparable<Customer> {
private String customerName;
private CustomerLevel level;
/**
* @return the customerName
*/
public String getCustomerName() {
return customerName;
}
public Customer(String customerName, CustomerLevel level) {
super();
this.customerName = customerName;
this.level = level;
}
/**
* @param customerName
* the customerName to set
*/
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
/**
* @return the level
*/
public CustomerLevel getLevel() {
return level;
}
/**
* @param level
* the level to set
*/
public void setLevel(CustomerLevel level) {
this.level = level;
}
@Override
public int compareTo(Customer o) {
return o.getLevel().ordinal()-this.level.ordinal();
}
public String toString(){
return (this.getCustomerName()+":"+this.getLevel().toString());
}
}
我们可以想象,在同一时间到银行办业务的人,优先级(业务类型)一样的肯定很多,则必须得有个先来后到不是,所以我引入了FIFOEntry,来保证相应的顺序:
package com.fcm.thread.banksample;
import java.util.concurrent.atomic.AtomicInteger;
public class FIFOEntry<E extends Comparable<? super E>> implements
Comparable<FIFOEntry<E>> {
final static AtomicInteger seq = new AtomicInteger();
final long seqNum;
final E entry;
public FIFOEntry(E entry) {
seqNum = seq.getAndIncrement();
this.entry = entry;
}
public E getEntry() {
return entry;
}
@Override
public int compareTo(FIFOEntry<E> other) {
int result = entry.compareTo(other.entry);
if (result == 0 && other.entry != this.entry) {
result = (seqNum < other.seqNum ? -1 : 1);
}
return result;
}
}
好,到现在可以由银行的职员根据相应的优先级取回对应的工作了:
package com.fcm.thread.banksample;
import java.util.concurrent.BlockingQueue;
public class BankService implements Runnable {
//working queue,it would be given by service manager
private final BlockingQueue<FIFOEntry<Customer>> customerQueue;
public BankService(BlockingQueue<FIFOEntry<Customer>> customerQueue) {
super();
this.customerQueue = customerQueue;
}
@Override
public void run() {
try {
while(!customerQueue.isEmpty()){
service(customerQueue.take().getEntry());
}
} catch (Exception e) {
Thread.currentThread().interrupt();
}
}
public void service(Customer c){
System.out.println(c.getCustomerName()+":"+c.getLevel().toString());
}
}