![JAVA程序设计技能教程第7章_第1页](http://file4.renrendoc.com/view10/M03/29/0F/wKhkGWV5qWOAT8BJAAFDkE_5RP8917.jpg)
![JAVA程序设计技能教程第7章_第2页](http://file4.renrendoc.com/view10/M03/29/0F/wKhkGWV5qWOAT8BJAAFDkE_5RP89172.jpg)
![JAVA程序设计技能教程第7章_第3页](http://file4.renrendoc.com/view10/M03/29/0F/wKhkGWV5qWOAT8BJAAFDkE_5RP89173.jpg)
![JAVA程序设计技能教程第7章_第4页](http://file4.renrendoc.com/view10/M03/29/0F/wKhkGWV5qWOAT8BJAAFDkE_5RP89174.jpg)
![JAVA程序设计技能教程第7章_第5页](http://file4.renrendoc.com/view10/M03/29/0F/wKhkGWV5qWOAT8BJAAFDkE_5RP89175.jpg)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第7章异常处理和多线程
任务一:掌握Java中对异常的处理
任务三:实训七异常处理与多线程编程实训
任务二:掌握程序对多线程的处理
7.1任务一掌握Java中对异常的处理
7.1.1异常类和异常处理机制1.异常类
Java语言采用面向对象的方法来处理异常,每个异常都是由异常类产生的对象,所有的异常类(java.lang.Exception)均继承自java.lang.Object中的java.lang.Throwable类。它提供了一些方法让我们能够了解异常产生的原因和一些相关的信息。Java中的异常类具有层次组织,Throwable类是Object类的直接子类,Throwable类又有Error类(错误类)和Exception类(异常类)两个直接子类,这两个子类又有许多各自的子类,如图7-1。图7-1异常类的继承结构2.异常处理机制Java语言提供的异常处理机制,由捕获异常和处理异常两部分组成。在Java程序的执行过程中,如果出现了异常事件,就会生成一个异常对象。生成的异常对象将传递给Java运行系统,这一异常的产生和提交过程称为抛出(throw)异常。当Java系统得到一个异常对象时,它将会寻找处理这一异常的代码。找到能够处理这种类型的异常的方法后,系统把当前异常对象交给这个方法进行处理,这一过程称为捕获(catch)异常。如果Java运行时系统找不到可以捕获异的方法,则运行时系统将终止,相应的Java程序也将退出。7.1.2程序中异常处理方法
1.捕获异常在Java中用try-catch-finally结构来捕获和处理异常,其语法结构为:
try {可能产生异常的程序代码块;} catch(<要捕获的异常类型1><变量名称1>)//要处理的第一种异常
{处理捕获到的异常的代码块;} catch(<要捕获的异常类型2><变量名称2>)//要处理的第二种异常
{处理捕获到的异常的代码块;} …… finally//最终处理语句
{无论是否抛出异常都要执行的代码;}说明:
try后面的{}用来选定捕获异常的范围,就是我们觉得哪段语句可能会出现异常我们就把这部分语句放到try后面的{}里,如果这一范围内的某条语句发生异常,程序就会跳出try部分,不再继续try块中剩余的语句,根据异常的类型来执行相应的catch语句块,去处理相应的异常。catch语句可以有多个,构成多重catch语句,处理不同类型的异常。如果有一个catch语句指定的异常类型与发生的异常类型相符,那么就会执行这个catch语句,其他的catch语句则会被跳过不被执行。如果没有抛出异常,那么try代码块就会结束,并且会跳过所有catch语句,从最后一个catch后面的第一个语句继续执行。因此,只有在有异常抛出时,才会执行catch语句。catch语句中定义变量的方法与在方法中定义参数相同,只不过这个变量对应的是一个对象实例。不论前面catch语句执不执行finally后面{}中的语句都会执行。【例7-3】加入异常处理的多异常程序importjavax.swing.JOptionPane;public
classArrayTest2{
static
voidarraylong() {
intinputvalue,i; Stringinput;
intarray[];
do { input=JOptionPane.showInputDialog("请输入数组长度:");//显示输入对话框
inputvalue=Integer.parseInt(input); //将输入的数据转换为整型
try { array=new
int[inputvalue];
for(i=0;i<5;i++)
{ System.out.println("输出array["+i+"]"+"="+array[i]+"i="+i); } }
catch(NegativeArraySizeExceptione) { JOptionPane.showMessageDialog(null,"数组长度不能为负数请重新输入"); //输出异常处理信息
}
catch(ArrayIndexOutOfBoundsExceptionf) { JOptionPane.showMessageDialog(null,"数组长度越界请重新输入"); } }while(inputvalue<5);//条件不符合时返回重新输入
JOptionPane.showMessageDialog(null,"数组长度是"+inputvalue,"数组长度是",JOptionPane.INFORMATION_MESSAGE); }
public
static
voidmain(String[]args) { Arraylong();}
}【例7-3】执行结果2.异常的捕获顺序
在程序中捕获的NegativeArraySizeException异常类和ArrayIndexOutOfBoundsException异常类都是Exception的子类,然而父子类之间是可以有自动类型转换运算的,这就导致了异常捕获时有先后顺序,如果我们将catch(NegativeArraySizeExceptione)改为catch(Exceptione),当产生ArrayIndexOutOfBoundsException异常时第一个catch就会先将这个异常捕获并转换为Exception,后一个catch就不起作用了,程序就会报错如图7-5。
图7-5需要指出的是Java系统本身给我们提供了几种显示信息的方法如:toString()方法会显示异常类的名称和产生的原因。getLocalizedMessage()方法和getMessage()方法会显示异常发生的原因但不会显示异常的名称。其中getLocalizedMessage()方法显示的信息会以该程序所在平台的语系所使用的文字为主。printStackTrace()方法会显示产生这个异常的相关类名称以及是第几行程序代码产生的这个异常。3.抛出异常(1)throws关键字的使用在方法中声明使用throws的具体格式为:返回类型方法名(参数1,参数2)throws异常类型1,异常类型2……{……}返回类型是方法的返回数据类型,参数是方法的参数,异常类型可以有多个用逗号隔开。我们可以将例7-3中在arraylong()方法中可能出现的异常抛出,由调用它的main()方法来处理。【例7-4】声明抛出异常程序importjavax.swing.JOptionPane;publicclassArrayTest3{ staticvoidarraylong()throwsNegativeArraySizeException,ArrayIndexOutOfBoundsException { intinputvalue,i; Stringinput; intarray[]; array=newint[5];input=JOptionPane.showInputDialog("请输入数组长度(必须为小于5的正整数):"); inputvalue=Integer.parseInt(input); for(i=0;i<inputvalue;i++) {System.out.println("输出array["+i+"]"+"="+array[i]+"i="+i);} } publicstaticvoidmain(String[]args) { try {arraylong();} catch(NegativeArraySizeExceptione) {JOptionPane.showMessageDialog(null,"数组长度不能为负数"); } catch(ArrayIndexOutOfBoundsExceptionf) {JOptionPane.showMessageDialog(null,"数值大于5数组长度越界");} } }(2)throw关键字的使用throw关键字主要是用在try块中,用来明确的抛出一个“异常”。throw关键字后面跟随一个从Throwable类中派生的异常对象,用来说明发出的异常类型。throw语句促使程序立即停止运行,并且执行最近能够处理指定对象的catch语句。如果异常在程序的其他地方产生,throw语句也可以放在try语句的后面。为了把异常处理控制传递给更高层的处理模块,还可以对截获的异常对象再一次实施throw操作。Throw语句的通常形式为:
throw异常类名;【例7-5】用throw语句抛出异常程序publicclassThrowtest1{staticvoidA() {System.out.println("方法A执行中");}
publicstaticvoidmain(String[]args){ try{A();thrownewRuntimeException("方法A出现异常"); } catch(Exceptione) {System.out.println("捕获方法A出现的异常");} finally {System.out.print("方法A结束");} }}说明:如果抛出异常而没有找到处理这个异常的代码,或者没有再次被抛出或者catch语句中捕获异常的类型与抛出的不一致则程序会报错。
throw与throws的区别在于:throw是语句抛出一个异常,throws是方法声明抛出一个异常;throw不能单独使用,throw要么和try-catch-finally语句配套使用,要么与throws配套使用,而throws可以单独使用,然后再由处理异常的方法捕获。
4.自定义异常类实现自定义异常类有两种方法:继承Throwable类或者Exception类。自定义异常类之间也可以有继承关系,在定义时需要为自定义异常类设计构造方法,以方便构造自定义异常对象。由于Exception是Throwable类的子类,所以我们自定义的异常类可以获得Throwable定义的方法。我们也可以在创建的异常类中覆盖一个或多个这样的方法。自定义异常类的基本形式如下所示:
class自定义异常extends父异常类名
{类体;}
【例7-6】自定义异常类程序classZiDingextendsException//自定义异常类{ inti; ZiDing(inta)//构造函数
{ i=a;} publicStringtoString()//覆盖父类方法
{ returni+"是非法操作数"; } }
publicclassFirstException{staticvoidjiancha(inta)throwsZiDing{if(a>100)thrownewZiDing(a);//抛出自定义类System.out.println(a+"是合法操作数");System.out.println("程序结束");}publicstaticvoidmain(Stringargs[]){try{jiancha(50);jiancha(101);}catch(ZiDinge)//捕获自定义类{System.out.println("捕获了异常"+e);}}}7.2.1多线程的概念多线程是相对于单线程而言的,指的是在一个程序中可以定义多个线程并同时运行它们,每个线程可以执行不同的任务。多线程的意义在于一个应用程序的多个逻辑单元可以并发地执行。但是多现程并不意味着多个用户进程在执行,操作系统也不把每个线程作为独立的进程来分配独立的系统资源。进程之间切换系统开销大,线程之间切换开销小。7.2任务二掌握程序对多线程的处理7.2.2实现多线程的两种方法我们有两种方法来实现多线程,一种方法是从Thread类继承,写一个Thread类的子类,在子类中重写run()方法覆盖掉Thread类中的run()方法,每个线程都是通过某个特定Thread对象的run()方法来完成其操作的,run()方法称为线程体。线程所要运行的程序代码就是run()方法中的程序代码,格式为:class类名extendsThread{……publicvoidrun(){方法体}……}【例7-7-1】继承Thread类publicstaticclassThread1extendsThread{publicvoidrun(){
System.out.println("A");
}
}
另一种方法是提供一个实现接口Runnable的类作为一个线程的目标对象,在初始化一个Thread类或者Thread子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体run()格式为:class类名implementsRunnable{……publicvoidrun(){方法体}……}【例7-7-2】实现Runnable接口publicstaticclassThread2implementsRunnable{publicvoidrun(){
System.out.println("1");
}}说明:这两种构造线程体方法各有优缺点,使用Runnable接口可以将CPU、代码和数据分开,形成清晰的模型,还可以从其他类继承。直接继承Thread类时,由于Java不支持多重继承所以不能再从其他类继承,但编写简单可以直接操纵线程。
7.2.3线程的生命周期和线程的控制1.线程的生命周期线程的生命周期可以分为5种状态:创建状态(newThread)、可运行状态(Runnable)、运行状态(Running)、阻塞态(Blocked)、死亡状态(Dead)。
2.线程的控制线程的控制主要是通过Thread中提供的线程状态转换的方法实现的。(1)start()方法start()方法使新生成的线程实体从新生状态转入可运行状态,如:
ThreadA=newThread();A.start();需要说明的是,一个thread对象只能调用一次strat方法,如果对一个已经启动的线程再调用start方法就会产生异常。
(2)sleep()方法
从sleep()方法的名字上就可以看出这个方法是让线程对象睡一会觉,想让线程对象睡多长时间我们只需把时间参数传入就可以了,只不过这个参数是以千分之一秒为单位的,如果想停一秒钟,就要输入1000。sleep()方法有两种格式sleep(longmillis)和sleep(longmillis,intnanos),nanos为附加时间单位为纳秒。当运行sleep()方法后线程就会暂停相应的时间,当暂停的时间到了以后,线程会转入可运行状态等待运行,而不是直接进入运行状态,传入的时间参数只是保证线程对象至少会停止的时间。需要指出的是在线程暂停过程中可能遇到外部中断异常,导致程序中断,所以需要进行异常处理。【例7-9】start()方法与
sleep()方法应用程序publicclassSleepTestextendsThread{Stringlight;SleepTest(Stringlight){ this.light=light;}publicvoidrun(){ try{ for(inti=1;i<=5;i++) {System.out.println(light+i+"次"); sleep(100); } } catch(Exceptione){ System.err.print(e); }}publicstaticvoidmain(String[]args){ newSleepTest("1号灯亮").start(); newSleepTest("2号灯亮").start();}}(3)yield()方法yield()方法使当前进程放弃运行,进入到可运行状态,重新排队等待运行,给其他可运行的进程一个运行的机会,但并不是一定就会轮到其他的线程运行,因为如果优先级相同调用yield()方法的线程有可能又被选中获得执行的机会,我们可以把例7-9中的sleep()换成yield()看一下执行结果,yield()方法不带参数。(4)wait()和notify()方法wait()方法的格式为wait(longtime)或wait(longtime,intnanos),time为等待的时间,单位为毫秒,nanos为附加等待时间,单位为纳秒。wait()方法使当前进程进入阻塞状态直到被唤醒或是等待的时间已到。wait()等价于wait(0),它使线程无限等待直到被唤醒。notify()方法用来唤醒一个正在等待的线程,一条notify();语句只能随机唤醒一个进程。使用notifyAll()方法可以唤醒所有在等待的进程。需要指出的是这三个方法只能用在synchronized方法里。(5)isAlive()方法isAlive()方法用来判断一个线程的run()方法是否还在执行,如果是则返回true,反之返回false。(6)join()方法如果一个线程在执行过程中需要等到另一个线程执行完才能继续执行就需要另一个进程调用join()方法,该方法也要捕获异常。join()方法也可以象wait()方法一样带参数表示需要另一个进程运行多长时间。【例7-10】join()方法应用,地铁建设工程程序publicclassJianZhuextendsThread{//建筑队类
publicvoidrun() { System.out.println("地铁建设中"); System.out.println("水泥用完了,通知运输队运输"); Threadyunshu=newYunShu();//创建运输队线程
yunshu.start(); System.out.println("建筑队等待水泥运到"); try{ yunshu.join(); }//等待运输到达
catch(Exceptione) {//防止在等待中出现异常中断
System.err.println("运输队途中遇阻"); System.err.println("建设工程停工"); } System.out.println("建设工程继续"); } }publicclassYunShuextendsThread{//运输队类
publicvoidrun(){ System.out.println("运输队出发,水泥运回需要三小时"); try{ for(inti=1;i<=3;i++)//运输所需时间
{ Thread.sleep(3000); System.out.print("\n等待"+i+"小时"); } } catch(Exceptione) { System.err.println("运输队途中遇阻"); } System.out.println("\n水泥运到"); } }publicclassDiTei{//地铁建设类
publicstaticvoidmain(Stringargs[]) {Threadjianzhu=newJianZhu();//创建建筑线程
jianzhu.start(); }}例7-10中建立了三个类,JianZhu类的线程在执行过程中需要YunShu类线程加入,线程yunshu调用了jion()方法,在线程yunshu执行完后线程jianzhu才继续执行,结果如图7-8。图7-8(7)getPriority()和setPriority()方法我们可以用setPriority()方法来改变一个线程的优先级,如:A.setPriority(Thread.MAX_PRIORITY-3)。用getPriority()方法返回一个线程的优先级。数值越大优先权就越高越先执行。每隔几毫秒,操作系统的调度器就会确定一次系统中等待执行的所有线程的优先级,并将时间片分配给优先级最高的线程。如果两个或更多的线程有相同的优先值,执行哪个线程将是不确定的。假设有A、B、C、D四个线程优先值相同,如果时间片先分给了线程A那么当这个时间片用完,操作系统就会将A转入可运行状态,然后从相同优先级的A、B、C、D四个线程中任选一个执行,A有可能又被重新选中获得执行。优先级低的线程也不是没有机会,只是机会要小一些。还有就是尽量不要通过改变进程的优先级来调度进程,这样做比较容易产生错误。7.2.4线程的同步由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。为有效避免了同一个数据对象被多个线程同时访问,Java语言提供了专门机制以解决这种冲突。由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块。
(1)synchronized方法:通过在方法声明中加入synchronized关键字来声明synchronized方法。如:publicsynchronizedvoid方法名(参数1,参数2);synchronized方法控制对类成员变量的访问:每个类实例对应一把锁,每个synchronized方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为synchronized的成员函数中至多只有一个处于可执行状态,从而有效避免了类成员变量的访问冲突。【例7-12】wait()和notify()方法与synchronized修饰符应用,大炮发射程序publicclassCannons{//大炮类privatebooleanshells=false;privateinti,j=0;synchronizedvoidshot(){//发射炮弹
while(!shells){ try{wait(); } catch(InterruptedExceptione){ System.out.print("程序中断");}} shells=false; i++; if(i>5)//发射5次后退出
{System.exit(1);} System.out.println("大炮第"+i+"次发送完毕,请装填炮弹"); notify();//唤醒装填手 }synchronizedvoidload(){ while(shells){ try{wait();} catch(InterruptedExceptione){ System.out.print("程序中断");}} shells=true; j++; if(j>5) {System.exit(1);} System.out.println("炮弹装填完毕"); notify();//通知炮手
} }classArtilleryextendsThre
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 短期农家乐场地租赁合同范本
- 农产品购销合同示范文本
- 战略合作合同范本(权威)
- 合同执行保证协议(银行函件版)
- 电子产品性能评估与验证方法研究
- 现代医疗体系下的中心静脉导管技术培训体系构建
- 2024年高中语文第二单元12电脑神童盖茨练习含解析粤教版选修传记蚜
- 2024-2025学年高中政治第二单元第六课第二框股票债券和保险练习含解析新人教版必修1
- 社交电商的全球化趋势及文化影响
- 用电设施的定期维护与检查重要性
- 房地产市场报告 -【成都】【锐理】2024年10月丨房地产市场月报
- 《护理礼仪与人际沟通》第五章
- 危急值的考试题及答案
- 2024年知识竞赛-竞彩知识考试近5年真题集锦(频考类试题)带答案
- 《算法设计与分析基础》(Python语言描述) 课件 第1章 绪论
- 初中地理课程标准测试题
- 高级农业经理人(三级)技能鉴定考试题及答案
- 灌砂法压实度自动计算表(华岩软件)
- 中华民族共同体的历史、现实与未来
- 幼儿园2024年春季开学预案
- 鲁科版小学四年级下册综合实践活动教案(适合山东科学技术版教材)
评论
0/150
提交评论