- 第一卷
- 第二卷
7.3.1生产者和消费者 多线程的一个重要特点是它们?reg;间可以互相通讯。你可以设计线程使用公用对象,每个线程都可以独立操作公用对象。典型的线程间通讯建立在生产者和消费者模型上:一个线程产生输出;另一个线程使用输入buffer 让我们创建一个简单的"AlphabetSoup"生产者和相应的消费者. 7.3.2生产者 生产者将从thread类里派生:
classProducerextendsThread {
privateSoupsoup;
privateStringalphabet=\"
ABCDEFGHIJKLMNOPQRSTUVWXYZ\";
publicProducer(Soups){
//Keepourowncopyofthesharedobjectsoup =s;
}
publicvoidrun(){
charc;
//Throw10lettersintothesoupfor(int
i=0;i soup.add(c);
//printarecordofosraddition
System.out.println(\"Added\"+c+\"tothesoup.\");
//waitabitbeforewe
addthenextlettertry{
sleep((int)(Math.random()*1000));
}catch (InterruptedExceptione){
}
}
}
}
注意我们创建了Soup类的一个实例。生产者用soup.add()函数来建立字符池。 7.3.3消费者 让我们看看消费者的程序:
classConsumerextendsThread{privateSoupsoup;
publicConsumer(Soups){
//keepourowncopyofthesharedobjectsoup=s;
}
publicvoidrun(){
charc;//Eat10lettersfromthealphabetsoup
for (intI=0;i
letterthatweretrieved
System.out.println(\"Atealetter:\"+c);
//try
{
sleep((int)(Math.raddom()*2000));
}catch(InterruptedExceptione){
}
}
}
}
同理,象生产者一样,我们用soup.eat()来处理信息。那么,Soup类到底干什么呢? 7.3.4监视 Soup类执行监视两个线程?reg;间传输信息的功能。监视是多线程中不可缺少的一部分,因为它保持了通讯的流?copy;。让我们看看Soup.java文件:
classSoup{
privatecharbuffer[]=newchar[6];
privateintnext=0;
//Flagstokeeptrackof
ourbufferstatusprivatebooleanisFull=false;
privatebooleanisEmpty =true;
publicsyschronizedchareat(){
//Wecan\'teatifthereisn\'tanything
inthebufferwhile(isEmpty==true){
try{
wait();
//we\'llexitthis
whenisEmptyturnsfalse
}catch(InterruptedExceptione){
}
}//decrement
thecount,sincewe\'regoingtoeatoneletternext--;
//Didweeatthe
lastletter?if(next==0){
isEmpty=true;
}//Weknowthebuffercan\'t
befull,becausewejustateisFull=false;
notify();//returntheletter
tothethreadthatiseatingreturn(buffer[next]);
}
//methodtoaddletterstothebufferpublicsynchronizedvoidadd(char c){
//Waitarounduntilthere\'sroomtoaddanotherletter
while(isFull ==true){
try{
wait();
//ThiswillexitwhenisFullturnsfalse
}catch (InterruptedExceptione){
}
}//addthelettertothenextavailablespot
buffer[next]=c;//Changethenextavailablespotnext++;//Arewefull;
if(next==6){
isFull=true;
}
isEmpty=false;
notify();
}
}
soup类包含两个重要特征:数据成员buffer[]是私有的,功能成员add()和eat()是公有的。 数据私有避免了生产者和消费者直接获得数据。直接访问数据可能造成错误。例如,如果消费者企图从空缓冲区里取出数据,你将得到不必要的异常,否则,你只能锁住进程。同步访问方法避免了破坏一个共享对象。当生产者向soup里加入一个字母时,消费者不能吃字符,诸如此类。这种同步是维持共享对象完整性的重要方面。notify()函数将唤醒每一个等待线程。等待线程将继续它的访问。 7.3.5联系起来 现在我们有一个生产者,一个消费者和一个共享对象,怎样实现它们的交互呢?我们只需要一个简单的控制程序来启动所有的线程并确信每一个线程都是访问的同一个共享对象。下面是控制程序的代码,
SoupTest.java:
classSoupTest{
publicstaticvoidmain(Stringargs[]){
Soups=new Soup();
Producerp1=newProducer(s);
Consumerc1=newConsumer(s);
p1.start();
c1.start();
}
}
7.3.6监视生产者 生产者/消费者模型程序经常用来实现远程监视功能,它让消费者看到生产者同用户的交互或同系统其它部分的交互。例如,在网络中,一组生产者线程可以在很多工作站上运行。生产者可以打印文档,文档打印后,一个标志将保存下来。一个(或多个?copy;消费者将保存标志并在晚上报告白天打印活动的情况。另外,还有例子在一个工作站是分出几个独立的窗口。一个窗口用作用户输入(生产者)另一个窗口作出对输入的反应(消费者)。