3A电子书 > 名著电子书 > Java语言入门 >

第10章

Java语言入门-第10章

小说: Java语言入门 字数: 每页4000字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!



=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'sroomtoaddanotherletterwhile(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;消费者将保存标志并在晚上报告白天打印活动的情况。另外,还有例子在一个工作站是分出几个独立的窗口。一个窗口用作用户输入(生产者)另一个窗口作出对输入的反应(消费者)。
7。4线程API列表
下面是一个常用的线程类的方法函数列表:类函数:以下是Thread的静态函数,即可以直接从Thread类调用。
currentThread返回正在运行的Thread对象yield停止运行当前线程,让系统运行下一个线程sleep(intn)让当前线程睡眠n毫秒对象函数:以下函数必须用Thread的实例对象来调用。
startstart函数告诉java运行系统为本线程建立一个执行环境,然后调用本线程的run()函数。run是运行本线程的将要执行的代码,也是Runnable接口的唯一函数。当一个线程初始化后,由start函数来调用它,一?copy;run函数返回,本线程也就终止了。stop让某线程马上终止,系统将删除本线程的执行环境suspend与stop函数不同,suspend将线程暂停执行,但系统不破坏线程的执行环境,你可以用resume来恢复本线程的执行resume恢复被挂起的线程进入运行状态setPriority(intp)给线程设置优先级getPriority返回线程的优先级setName(Stringname)给线程设置名称getName取线程的名称
本章小结:
1。多线程是java语言的重要特点,java语言用Thread类封装了线程的所有操作。2。线程的接口名为Runnable3。线程间同步机制为synchronized关键词4。线程间通讯靠wait与notify消息
第八章Java的”异常”
”异常”指的是程序运行时出现的非正常情况。在用传统的语言编程时,程序员只能通过函数的返回值来发出错误信息。这易于导致很多错误,因为在很多情况下需要知道错误产生的内部细节。通常,用全局变量errno来存储”异常”的类型。这容易导致误用,因为一个errno的值有可能在被处理?reg;前被另外的错误覆盖掉。即使最优美的C语言程序,为了处理”异常”情况,也常求助于goto语句。Java对”异常”的处理是面向对象的。一个Java的Exception是一个描述”异常”情况的对象。当出现”异常”情况时,一个Exception对象就产生了,并放到产生这个”异常”的成员函数里。
8。1基础
Java的”异常”处理是通过5个关键词来实现的:try;catch;throw;throws和finally。用try来执行一段程序,如果出现”异常”,系统抛出(throws?copy;一个”异常”,你可以通过它的类型来捕捉(catch?copy;它,或最后(finally?copy;由缺省处理器来处理。下面是”异常”处理程序的基本形式:try{//程序块}catch(ExceptionType1e){//对ExceptionType1的处理}catch(ExceptionType2e){//对ExceptionType2的处理throw(e);//再抛出这个”异常”}finally{}
8。2”异常”的类型
在”异常”类层次的最上层有一个单独的类叫做Throwable。这个类用来表示所有的”异常”情况。每个”异常”类型都是Throwable的子类。Throwable有两个直接的子类。一类是Exception,是用户程序能够捕捉到的”异常”情况。我们将通过产生它的子类来创建自己的”异常”。另一类是Error,它定义了那?copy;通常无法捕捉到的”异常”。要谨慎使用Error子类,因为它们通常会导致灾难性的失败。在Exception中有一个子类RuntimeException,它是程序运行时自动地对某?copy;错误作出反应而产生的。
8。3不捕捉”异常”
”异常”对象是Java在运行时对某?copy;”异常”情况作出反应而产生的。例如,下面这个小程序包含一个整数被0除的”异常”。
classExc0{publicstaticvoidmain(Stringargs''){intd=0;inta=42/d;}}
当Java执行这个除法时,由于分母是0,就会构造一个”异常”对象来使程序停下来并处理这个错误情况,在运行时”抛出”(throw?copy;这个”异常”。说”抛出”是因为它象一个滚烫的马铃薯,你必须把它抓住并立即处理。程序流将会在除号操作符处被打断,然后检查当前的调用堆栈来查找”异常”。一个”异常”处理器是用来立即处理”异常”情况的。在这个例子里,我们没有编一个”异常”处理器,所以缺省的处理器就发挥作用了。缺省的处理器打印Exception的字符?reg;值和发生”异常”的地点。
下面是我们的小例子的输出。
C:》javaExc0java。lang。arithmeticException:/byzeroatExc0。main(Exc0。java:4)
8。4try与catch
通常我们希望自己来处理”异常”并继续运行。可以用try来指定一块预防所有”异常”的的程序。紧跟在try程序后面,应包含一个catch子句来指定你想要捕捉的”异常”的类型。例如,下面的例子是在前面的例子的基础上构造的,但它包含一个try程序块和一个catch子句。classexc1{publicstaticvoidmain(stringargs''){try{intd=0;inta=42/d;}catch(arithmeticexceptione){system。out。println(”divisionbyzero”);}}}
catch子句的目标是解决”异常”情况,把变量设到合理的状态,并象没有出错一样继续运行。如果一个子程序不处理某个”异常”,则返到上一级处理,直到最外一级。
8。5多个catch子句
在某情况下,同一段程序可能产生不止一种”异常”情况。你可以放置多个catch子句,其中每一种”异常”类型都将被检查,第一个与?reg;匹配的就会被执行。如果一个类和其子类都有的话,应把子类放在前面,否则将永远不会到达子类。下面是一个有两个catch子句的程序的例子。
classMultiCatch{publicstaticvoidmain(Stringargs''){try{inta
=args。length;System。out。println(”a=”+a);intb=42/a;intc''=
{1};c'42'=99;}catch(ArithmeticExceptione){System。out。println(”div
by0:”+e);}catch(ArrayIndexOutOfBoundsExceptione)
{system。out。println(”arrayindexoob:”+e);}}}
如果在程序运行时不跟参数,将会引起一个0做除数的”异常”,因为a的值为0。如果我们提?copy;一个命令行参数,将不会产生这个”异常”,因为a的值大于0。但会引起一个ArrayIndexOutOfBoundexception的”异常”,因为整型数组c的长度是1,却给c'42'赋值。下面是以上两种情况的运行结果。
C:》javaMultiCatcha=0divby0:java。lang。arithmeticexception:/by
zeroC:》javaMutiCatch1a=1arrayindexoob:
java。lang。ArrayIndexOutOfBoundsException:42
8。6try语句的嵌套
你可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部,写另一个try语句保护其他代码。每当遇到一个try语句,”异常”的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种”异常”进行处理,堆栈就会展开,直到遇到有处理这种”异常”的try语句。下面是一个try语句嵌套的例子。
classMultiNest{staticvoidprocedure(){try{intc''={1}:c'42'
=99;}catch(ArrayIndexOutOfBoundsexceptione)
{System。out。println(”arrayindexoob:”+e);}}publicstaticvoid
main(Stringargs''){try{inta=args。length;system。out。println(”a
=”+a);intb=42/a;procedure();}catch(arithmeticExceptione)
{System。out。println(”divby0:”+e);}}}
成员函数procedure里有自己的try/catch控制,所以main不用去处理ArrayIndexOutOfBoundsException。
8。7throw语句
throw语句用来明确地抛出一个”异常”。首先,你必须得到一个Throwable的实例的控制柄,通过参数传到catch子句,或者用new操作符来创建一个。下面是throw语句的通常形式。
throwThrowableInstance;
程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中从里向外寻找含有与其匹配的catch子句的try块。下面是一个含有throw语句的例子。
classThrowDemo{staticvoiddemoproc(){try{thrownewNullPointerException(”de3mo”);}catch(NullPointerExceptione){System。out。println(”caughtinsidedemoproc”);throwe;}}publicstaticvoidmain(Stringargs''){try{demoproc();}
catch(NullPointerExceptione){system。out。println(”recaught:”+e);}}}
8。8throws语句
throws用来标明一个成员函数可能抛出的各种”异常”。对大多数Exception子类来说,Java编译器会强迫你声明在一个成员函数中抛出的”异常”的类型。如果”异常”的类型是Error或RuntimeException,或它们的子类,这个规则不起作用,因为这?copy;在程序的正常部分中是不期待出现的。如果你想明确地抛出一个RuntimeException,你必须用throws语句来声明它的类型。这就重新定义了成员函数
的定义语法:typemethod…name(arg…list)throwsexception…list{}
下面是一段程序,它抛出了一个”异常”,但既没有捕捉它,也没有用throws来声明。这在编译时将不会通过。
classThrowsDemo1{staticvoidprocedure()'System。out。println(”inside
procedure”);thrownewIllegalAccessException(”demo”);}publicstatic
voidmain(Stringargs''){procedure();}}
为了让这个例子编译过去,我们需要声明成员函数procedure抛出了IllegalAccessException,并且在调用它的成员函数main里捕捉它。下面是正确的例子:
classThrowsDemo{staticvoidprocedure()throwsIllegalAccessException
{System。out。println(”insideprocedure”);thrownew
IllegalAccessException(”demo”);}publicstaticvoidmain(Stringargs'')
{try{procedure();}catch(IllegalAccessExceptione)
{System。out。println(”caught”+e);}}}
下面是输出结果:
C:》javaThrowsDemoinsideprocedurecaught
java。lang。IllegalAccessException:demo
8。9finally
当一个

返回目录 上一页 下一页 回到顶部 0 0

你可能喜欢的