这段时间在看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()); } }