...从BlockingQueue也可以看出,它和UNIXpȝ下面的Pipe十分怼。所不同的不q是两点Q首先,pipe是进E间的,命名道甚至可以在非亲缘q程间用,而BlockingQueue 目前只是U程间的通信手段。当Ӟ׃java本n强大的动态类装蝲功能Q这个缺陷对javaE序之间的沟通限制ƈ不大。其ơ,pipe是基于字节流的,而BlockingQueue? Z对象的,q得BlockingQueue更加易用Q不q却让BlockingQueuel定了Java语言Qɘq一步成量本地q程通信工具的难度增大?
BlockingQueue<String> q =new ArrayBlockingQueue<String> (10);
...
public void supply () {
q.put("product by "+Thread.currentThread().getId()+":"+(++productNo));
}
...
public void cunsume () {
String product =q.take();
System.out.println("consume product:"+product);
}
从前面对生/消费模型的行为方式可以看出,生/消费模型着重于规范消费者的行ؓ模式Q当消费速度过生速度的时候,消费者就会被d。而对于生产者的行ؓ则没? 规定。当生速度过消费速度Q生产者的行ؓ模式可以分ؓ以下几种Q? #当积压的产品辑ֈ一定数量时Q生产者被d #无论有多积压品,生者都不会被阻? #不能有Q何积压品,生者在当前产品未被消费之前Q会被阻? 对于产品来说Q也有不同的行ؓ模式 #产品只有在被生出来一D|间之后才能被消费(先花Ҏ间晾晑ֹQ? #不同cd的品被消费的优先不同(有钻石的话,黄金先放一边吧:))
Ҏ生者行为模式的不同Concurrent包提供了不同的BlockingQueue的实?
||QueueU类||行ؓ描述
|ArrayBlockingQueue
q些不同的行为模式中Q较为常见的除了ArrayBlockingQueue和LinkedBlockingQueue之外QPriorityBlockingQueue也非帔R要。D例来_如果我们利用BlockingQueue 来实C个邮件系l(著名的qmail是利用pipe技术构建的核心架构Q。我们知道邮件有不同的别,如果当前队列里有加急邮仉要处理的话,pȝ优先处理加急邮件? 我们以邮g传递ؓ例子Q说明PriorityBlockingQueue的用方法。(注:q里的这个邮件模型只是一个非常简陋的模型Q用来说明PriorityBlockingQueue的用方法而已Q? 和实际应用有很大的差距)
首先Q我们需要了解邮件传递过E的基本模型。在q个单的邮g传送模型中涉及C列概? *MDA: Mail Deliver Agent, 负责接受指定用户的邮件? *MTA: Mail Transfer Agent, 负责接受q程传送过来的邮gQƈ其传送给收g人的MDA 它们和邮件用户之间的关系如下?/p>
public class MailQueue<E> extends PriorityBlockingQueue<E>{Z能够Ҏ收g人的Mail Address扑ֈ相应的Mail Queue, 使用一个MailQueueFactory来生MailQueue
public E take () throws InterruptedException {
E ren =super.take();
Utils._log("take:"+ren);
return ren;
}
public void put (E o) {
super.put(o);
Utils._log("put:"+o);
}
}
public class MailQueueFactory {需要注意的是,我们在MailQueueFactory里面使用了ConcurrentHashMapQ而不是传l的Hashtable, 虽然Hashtable是thread-safeQ但是缺乏putIfAbsentq样? 原子函数Q如果不心设计的话Q会造成对同一个MailQueue重复初始化,从而导致死锁问题? 下面看Mail的定?
//A ConcurrentHashMap is used here instead of Hashtable
static ConcurrentHashMap<MailAccount,MailQueue<Mail>> mailQueues =
new ConcurrentHashMap<MailAccount,MailQueue<Mail>>();
public static BlockingQueue<Mail> getMailQueue (MailDeliverer e) {
return getMailQueue(e.getMailAccount());
}
public static BlockingQueue<Mail> getReceiveMailQueue (Mail m) {
return getMailQueue (m.getReceiver());
}
public static BlockingQueue<Mail> getMailQueue (MailAccount e) {
mailQueues.putIfAbsent (e,new MailQueue<Mail>());
MailQueue<Mail> mailQ =mailQueues.get(e);
return mailQ;
}
}
public class Mail implements Comparable{q里值得注意的是AtomicInteger的用,它被用来做内部serialNumber的生。另外就是compareTo函数的用,PriorityBlockingQueue使用Comparable接口来判定元素的优先U别。这里所定义的优先如下Q? *如果邮gcd相同Q则序列号小的邮件有较大的优先 *如果邮gcd不同Q则emergencyMail有较大的优先U? 最后是Deliver Agent ?Transfer Agent的代?
public final static int emergencyMail =0;
public final static int normalMail =1;
static AtomicInteger serialCounter =new AtomicInteger(0);
private int mailLevel;
private int serialNumber =serialCounter.addAndGet(1);
private MailAccount receiver =null;
private MailAccount sender =null;
private Date sendTime =new Date();
public Mail (String from, String to, int level) {
...
}
//Get functions
...
public int compareTo(Object o) {
if (o instanceof Mail) {
return compareTo ((Mail)o);
}
return 0;
}
public int compareTo (Mail o) {
if (o.mailLevel==this.mailLevel) { //Same level, compare the serial no
if (o.serialNumber==this.serialNumber)
return 0;
if (o.serialNumber>this.serialNumber)
return -1;
return 1;
}
if (this.mailLevel==emergencyMail) return -1;
return 1;
}
//Other functions
...
}
public class MailDeliverer {
MailAccount mailAccount =null;
public MailDeliverer (MailAccount account) {
this.mailAccount =account;
}
public MailAccount getMailAccount() {
return mailAccount;
}
public Mail retrieveMail () {
Mail mail =null;
while (mail==null) {
try {
mail =MailQueueFactory.getMailQueue(this).take();
}catch (Exception e) {
Utils._log("Encounter Exception",e);
}
}
return mail;
}
}
public class MailTransfer {
private static MailTransfer instance =new MailTransfer ();
private MailTransfer () { }
public static MailTransfer getInstance () {
return instance;
}
public void processMail (Mail m) {
BlockingQueue mailQ =MailQueueFactory.getReceiveMailQueue(m);
try {
mailQ.put(m);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}