收藏 分享(赏)

ava论文多线程和异常处理 p11.doc

上传人:cjc2202537 文档编号:1137142 上传时间:2018-06-14 格式:DOC 页数:12 大小:105.50KB
下载 相关 举报
ava论文多线程和异常处理 p11.doc_第1页
第1页 / 共12页
ava论文多线程和异常处理 p11.doc_第2页
第2页 / 共12页
ava论文多线程和异常处理 p11.doc_第3页
第3页 / 共12页
ava论文多线程和异常处理 p11.doc_第4页
第4页 / 共12页
ava论文多线程和异常处理 p11.doc_第5页
第5页 / 共12页
点击查看更多>>
资源描述

1、多线程和异常处理1、多线程一、操作系统中线程和进程的概念现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在 Windows 系统中,一个运行的 exe 就是一个进程。线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe 进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。“同时”执行是人的感觉,在线程之间实际上轮换执行。二、Java 中的线程在 Java 中,“线程”指两件不同的事情:线程的执行。使用java.lang.Thre

2、ad 类或者 java.lang.Runnable 接口编写代码来定义、实例化和启动新线程。一个 Thread 类实例只是一个对象,像 Java 中的任何其他对象一样,具有变量和方法,生死于堆上。Java 中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。一个 Java 应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。一旦创建一个新的线程,就产生一个新的调用栈。线程总体分两类:用户线程和守候线程。当所有用户线程执行完毕的时候,JVM 自动关闭。但是守候线程却不独立于 JVM,守候线程一般是由操作系统或者用户自己创建的Java

3、线程:创建与启动一、定义线程1、扩展 java.lang.Thread 类。 此类中有个 run()方法,应该注意其用法:public void run()如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable对象的 run 方法;否则,该方法不执行任何操作并返回。Thread 的子类应该重写该方法。2、实现 java.lang.Runnable 接口。void run()使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。方法 run 的常规协定是,它可能执行任何所需的操作。三、启动线程在线程的 Th

4、read 对象上调用 start()方法,而不是 run()或者别的方法。在调用 start()方法之前:线程处于新状态中,新状态指有一个 Thread 对象,但还没有一个真正的线程。在调用 start()方法之后:发生了一系列复杂的事情启动新的执行线程(具有新的调用栈);该线程从新状态转移到可运行状态;当该线程获得机会执行时,其目标 run()方法将运行。对 Java 来说,run()方法没有任何特别之处。像 main()方法一样,它只是新线程知道调用的方法名称(和签名)。因此,在 Runnable 上或者 Thread 上调用 run 方法是合法的。但并不启动新的线程。五、一些常见问题1、

5、线程的名字,一个运行中的线程总是有名字的,名字有两个来源,一个是虚拟机自己给的名字,一个是你自己的定的名字。在没有指定线程名字的情况下,虚拟机总会为线程指定名字,并且主线程的名字总是 mian,非主线程的名字不确定。2、线程都可以设置名字,也可以获取线程的名字,连主线程也不例外。3、获取当前线程的对象的方法是:Thread.currentThread();4、在上面的代码中,只能保证:每个线程都将启动,每个线程都将运行直到完成。一系列线程以某种顺序启动并不意味着将按该顺序执行。对于任何一组启动的线程来说,调度程序不能保证其执行次序,持续时间也无法保证。5、当线程目标 run()方法结束时该线程

6、完成。6、一旦线程启动,它就永远不能再重新启动。只有一个新的线程可以被启动,并且只能一次。一个可运行的线程或死线程可以被重新启动。7、线程的调度是 JVM 的一部分,在一个 CPU 的机器上上,实际上一次只能运行一个线程。一次只有一个线程栈执行。JVM 线程调度程序决定实际运行哪个处于可运行状态的线程。众多可运行线程中的某一个会被选中做为当前线程。可运行线程被选择运行的顺序是没有保障的。8、尽管通常采用队列形式,但这是没有保障的。队列形式是指当一个线程完成“一轮”时,它移到可运行队列的尾部等待,直到它最终排队到该队列的前端为止,它才能被再次选中。事实上,我们把它称为可运行池而不是一个可运行队列

7、,目的是帮助认识线程并不都是以某种有保障的顺序排列唱呢个一个队列的事实。9、尽管我们没有无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。Java 线程:线程栈模型与线程的变量要理解线程调度的原理,以及线程执行过程,必须理解线程栈模型。线程栈是指某时刻时内存中线程调度的栈信息,当前调用的方法总是位于栈顶。线程栈的内容是随着程序的运行动态变化的,因此研究线程栈必须选择一个运行的时刻(实际上指代码运行到什么地方)。Java 线程:线程状态的转换一、线程状态线程的状态转换是线程控制的基础。线程状态总的可分为五大状态:分别是生、死、可运行、运行、等待/阻塞。描述如下:1、新状态:线程对象已

8、经创建,还没有在其上调用 start()方法。2、可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当 start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。3、运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。4、等待/阻塞/睡眠状态:这是线程有资格运行时它所处的状态。实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。换句话说,它是可运行的,但是如果某件事件出现,他可能返回到可运行状态。死亡态:当线程的 r

9、un()方法完成时就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。如果在一个死去的线程上调用 start()方法,会抛出java.lang.IllegalThreadStateException 异常。二、阻止线程执行对于线程的阻止,考虑一下三个方面,不考虑 IO 阻塞的情况:睡眠;等待;因为需要一个对象的锁定而被阻塞。1、睡眠Thread.sleep(long millis)和 Thread.sleep(long millis, int nanos)静态方法强制当前正在执行的线程休眠(暂停执行),以“减慢线程”。当线程睡眠时,它入睡在某个地

10、方,在苏醒之前不会返回到可运行状态。当睡眠时间到期,则返回到可运行状态。线程睡眠的原因:线程执行太快,或者需要强制进入下一轮,因为 Java 规范不保证合理的轮换。睡眠的实现:调用静态方法。try Thread.sleep(123); catch (InterruptedException e) e.printStackTrace(); 睡眠的位置:为了让其他线程有机会执行,可以将 Thread.sleep()的调用放线程 run()之内。这样才能保证该线程执行过程中会睡眠。多线程总结:要认识多线程就要从操作系统的原理说起。以前古老的 DOS 操作系统(V 6.22)是单任务的,还没有线程的概

11、念,系统在每次只能做一件事情。比如你在 copy 东西的时候不能 rename 文件名。为了提高系统的利用效率,采用批处理来批量执行任务。现在的操作系统都是多任务操作系统,每个运行的任务就是操作系统所做的一件事情,比如你在听歌的同时还在用 MSN 和好友聊天。听歌和聊天就是两个任务,这个两个任务是“同时”进行的。一个任务一般对应一个进程,也可能包含好几个进程。比如运行的 MSN 就对应一个 MSN 的进程,如果你用的是windows 系统,你就可以在任务管理器中看到操作系统正在运行的进程信息。 一般来说,当运行一个应用程序的时候,就启动了一个进程,当然有些会启动多个进程。启动进程的时候,操作系

12、统会为进程分配资源,其中最主要的资源是内存空间,因为程序是在内存中运行的。在进程中,有些程序流程块是可以乱序执行的,并且这个代码块可以同时被多次执行。实际上,这样的代码块就是线程体。线程是进程中乱序执行的代码流程。当多个线程同时运行的时候,这样的执行模式成为并发执行。 多线程的目的是为了最大限度的利用 CPU 资源。 Java 编写程序都运行在在 Java 虚拟机(JVM)中,在 JVM 的内部,程序的多任务是通过线程来实现的。每用 java 命令启动一个 java 应用程序,就会启动一个 JVM 进程。在同一个 JVM 进程中,有且只有一个进程,就是它自己。在这个 JVM 环境中,所有程序代

13、码的运行都是以线程来运行。 一般常见的 Java 应用程序都是单线程的。比如,用 java 命令运行一个最简单的 HelloWorld 的 Java 应用程序时,就启动了一个 JVM 进程,JVM 找到程序程序的入口点 main(),然后运行 main()方法,这样就产生了一个线程,这个线程称之为主线程。当 main 方法结束后,主线程运行完成。JVM 进程也随即退出 。 对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信很容易,速度也很快。不同的进程因为处于不同的内存块,因此进程之间的

14、通信相对困难。实际上,操作的系统的多进程实现了多任务并发执行,程序的多线程实现了进程的并发执行。多任务、多进程、多线程的前提都是要求操作系统提供多任务、多进程、多线程的支持。在 Java 程序中,JVM 负责线程的调度。线程调度是值按照特定的机制为多个线程分配 CPU 的使用权。调度的模式有两种:分时调度和抢占式调度。分时调度是所有线程轮流获得 CPU 使用权,并平均分配每个线程占用 CPU 的时间;抢占式调度是根据线程的优先级别来获取 CPU 的使用权。JVM 的线程调度模式采用了抢占式模式。 所谓的“并发执行”、“同时”其实都不是真正意义上的“同时”。众所周知,CPU 都有个时钟频率,表示

15、每秒中能执行 cpu 指令的次数。在每个时钟周期内,CPU 实际上只能去执行一条(也有可能多条)指令。操作系统将进程线程进行管理,轮流(没有固定的顺序)分配每个进程很短的一段是时间(不一定是均分),然后在每个线程内部,程序代码自己处理该进程内部线程的时间分配,多个线程之间相互的切换去执行,这个切换时间也是非常短的。因此多任务、多进程、多线程都是操作系统给人的一种宏观感受,从微观角度看,程序的运行是异步执行的。用一句话做总结:虽然操作系统是多线程的,但 CPU 每一时刻只能做一件事,和人的大脑是一样的。2、异常处理Java 异常处理总结 异常处理是程序设计中一个非常重要的方面,也是程序设计的一大

16、难点,从 C 开始,你也许已经知道如何用 if.else.来控制异常了,也许是自发的,然而这种控制异常痛苦,同一个异常或者错误如果多个地方出现,那么你每个地方都要做相同处理,感觉相当的麻烦!Java 语言在设计的当初就考虑到这些问题,提出异常处理的框架的方案,所有的异常都可以用一个类型来表示,不同类型的异常对应不同的子类异常(这里的异常包括错误概念),定义异常处理的规范,在 1.4 版本以后增加了异常链机制,从而便于跟踪异常!这是 Java 语言设计者的高明之处,也是Java 语言中的一个难点,下面是我对 Java 异常知识的一个总结。一、Java 异常的基础知识异常是程序中的一些错误,但并不

17、是所有的错误都是异常,并且错误有时候是可以避免的。比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用 System.out.println(11/0),那么你是因为你用 0 做了除数,会抛出 java.lang.ArithmeticException 的异常。有些异常需要做处理,有些则不需要捕获处理,后面会详细讲到。天有不测风云,人有旦夕祸福,Java 的程序代码也如此。在编程过程中,首先应当尽可能去避免错误和异常发生,对于不可避免、不可预测的情况则在考虑异常发生时如何处理。Java 中的异常用对象来表示。Java 对异常的处理是按异常分类处理

18、的,不同异常有不同的分类,每种异常都对应一个类型(class),每个异常都对应一个异常(类的)对象。异常类从哪里来?有两个来源,一是 Java 语言本身定义的一些基本异常类型,二是用户通过继承 Exception 类或者其子类自己定义的异常。Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。异常的对象从哪里来呢?有两个来源,一是 Java 运行时环境自动抛出系统生成的异常,而不管你是否愿意捕获和处理,它总要被抛出!比如除数为 0 的异常。二是程序员自己抛出的异常,这个异常可以是程序员自己定义的,也可以是 Java 语言中定义的,用 thro

19、w 关键字抛出异常,这种异常常用来向调用者汇报异常的一些信息。异常是针对方法来说的,抛出、声明抛出、捕获和处理异常都是在方法中进行的。Java 异常处理通过 5 个关键字 try、catch、throw、throws、finally 进行管理。基本过程是用 try 语句块包住要监视的语句,如果在 try 语句块内出现异常,则异常会被抛出,你的代码在 catch 语句块中可以捕获到这个异常并做处理;还有以部分系统生成的异常在 Java 运行时自动抛出。你也可以通过throws 关键字在方法上声明该方法要抛出异常,然后在方法内部通过 throw 抛出异常对象。finally 语句块会在方法执行 r

20、eturn 之前执行,一般结构如下:try程序代码catch(异常类型 1 异常的变量名 1)程序代码catch(异常类型 2 异常的变量名 2)程序代码finally程序代码catch 语句可以有多个,用来匹配多个异常,匹配上多个中一个后,执行catch 语句块时候仅仅执行匹配上的异常。catch 的类型是 Java 语言中定义的或者程序员自己定义的,表示代码抛出异常的类型,异常的变量名表示抛出异常的对象的引用,如果 catch 捕获并匹配上了该异常,那么就可以直接用这个异常变量名,此时该异常变量名指向所匹配的异常,并且在 catch 代码块中可以直接引用。这一点非常非常的特殊和重要!Jav

21、a 异常处理的目的是提高程序的健壮性,你可以在 catch 和 finally 代码块中给程序一个修正机会,使得程序不因异常而终止或者流程发生以外的改变。同时,通过获取 Java 异常信息,也为程序的开发维护提供了方便,一般通过异常信息就很快就能找到出现异常的问题(代码)所在。Java 异常处理是 Java 语言的一大特色,也是个难点,掌握异常处理可以让写的代码更健壮和易于维护。三、Java 异常处理机制对于可能出现异常的代码,有两种处理办法:第一、在方法中用 try.catch 语句捕获并处理异常,catach 语句可以有多个,用来匹配多个异常。例如:public void p(int x)

22、try.catch(Exception e).finally.第二、对于处理不了的异常或者要转型的异常,在方法的声明处通过throws 语句抛出异常。例如:public void test1() throws MyException.if(.)throw new MyException(); 如果每个方法都是简单的抛出异常,那么在方法调用方法的多层嵌套调用中,Java 虚拟机会从出现异常的方法代码块中往回找,直到找到处理该异常的代码块为止。然后将异常交给相应的 catch 语句处理。如果 Java 虚拟机追溯到方法调用栈最底部 main()方法时,如果仍然没有找到处理异常的代码块,将按照下面的

23、步骤处理:第一、调用异常的对象的 printStackTrace()方法,打印方法调用栈的异常信息。第二、如果出现异常的线程为主线程,则整个程序运行终止;如果非主线程,则终止该线程,其他线程继续运行。通过分析思考可以看出,越早处理异常消耗的资源和时间越小,产生影响的范围也越小。因此,不要把自己能处理的异常也抛给调用者。还有一点,不可忽视:finally 语句在任何情况下都必须执行的代码,这样可以保证一些在任何情况下都必须执行代码的可靠性。比如,在数据库查询异常的时候,应该释放 JDBC 连接等等。finally 语句先于 return 语句执行,而不论其先后位置,也不管是否 try 块出现异常

24、。finally 语句唯一不被执行的情况是方法执行了 System.exit()方法。System.exit()的作用是终止当前正在运行的 Java 虚拟机。finally 语句块中不能通过给变量赋新值来改变 return的返回值,也建议不要在 finally 块中使用 return 语句,没有意义还容易导致错误。最后还应该注意一下异常处理的语法规则:第一、try 语句不能单独存在,可以和 catch、finally 组成 try.catch.finally、try.catch、try.finally 三种结构,catch 语句可以有一个或多个,finally 语句最多一个,try、catch

25、、finally 这三个关键字均不能单独使用。第二、try、catch、finally 三个代码块中变量的作用域分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。第三、多个 catch 块时候,Java 虚拟机会匹配其中一个异常类或其子类,就执行这个 catch 块,而不会再执行别的 catch 块。第四、throw 语句后不允许有紧跟其他语句,因为这些没有机会执行。第五、如果一个方法调用了另外一个声明抛出异常的方法,那么这个方法要么处理异常,要么声明抛出。那怎么判断一个方法可能会出现异常呢?一般来说,方法声明的时候用了 throws 语句,方法中有 thro

26、w 语句,方法调用的方法声明有 throws关键字。throw 和 throws 关键字的区别throw 用来抛出一个异常,在方法体内。语法格式为:throw 异常对象。throws 用来声明方法可能会抛出什么异常,在方法名后,语法格式为:throws 异常类型 1,异常类型 2.异常类型 n。四、如何定义和使用异常类1、使用已有的异常类,假如为 IOException、SQLException。try程序代码catch(IOException ioe)程序代码catch(SQLException sqle)程序代码finally程序代码2、自定义异常类创建 Exception 或者 Runt

27、imeException 的子类即可得到一个自定义的异常类。例如:public class MyException extends Exceptionpublic MyException()public MyException(String smg)super(smg);3、使用自定义的异常用 throws 声明方法可能抛出自定义的异常,并用 throw 语句在适当的地方抛出自定义的异常。例如:在某种条件抛出异常public void test1() throws MyException.if(.)throw new MyException();将异常转型(也叫转译),使得异常更易读易于理解p

28、ublic void test2() throws MyException.try.catch(SQLException e).throw new MyException();还有一个代码,很有意思:public void test2() throws MyException.try . catch (MyException e) throw e; 这段代码实际上捕获了异常,然后又和盘托出,没有一点意义,如果这样还有什么好处理的,不处理就行了,直接在方法前用 throws 声明抛出不就得了。异常的捕获就要做一些有意义的处理。五、运行时异常和受检查异常Exception 类可以分为两种:运行时异

29、常和受检查异常。1、运行时异常RuntimeException 类及其子类都被称为运行时异常,这种异常的特点是Java 编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用 try.catch 语句捕获它,也没有用 throws 字句声明抛出它,还是会编译通过。例如,当除数为零时,就会抛出 java.lang.ArithmeticException 异常。2、受检查异常除了 RuntimeException 类及其子类外,其他的 Exception 类及其子类都属于受检查异常,这种异常的特点是要么用 try.catch 捕获处理,要么用throws 语句声明抛出,否则编译不会通过

30、。3、两者的区别运行时异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误的操作。一旦出现错误,建议让程序终止。受检查异常表示程序可以处理的异常。如果抛出异常的方法本身不处理或者不能处理它,那么方法的调用者就必须去处理该异常,否则调用会出错,连编译也无法通过。当然,这两种异常都是可以通过程序来捕获并处理的,比如除数为零的运行时异常:public class HelloWorld public static void main(String args) System.out.println(“Hello World!“); trySystem.out.println(1/0)

31、;catch(ArithmeticException e)System.out.println(“除数为 0!“);System.out.println(“除数为零后程序没有终止!“); 4、运行时错误Error 类及其子类表示运行时错误,通常是由 Java 虚拟机抛出的,JDK 中与定义了一些错误类,比如 VirtualMachineError和 OutOfMemoryError,程序本身无法修复这些错误.一般不去扩展 Error 类来创建用户自定义的错误类。而 RuntimeException 类表示程序代码中的错误,是可扩展的,用户可以创建特定运行时异常类。Error(运行时错误)和运行

32、时异常的相同之处是:Java 编译器都不去检查它们,当程序运行时出现它们,都会终止运行。5、最佳解决方案对于运行时异常,我们不要用 try.catch 来捕获处理,而是在程序开发调试阶段,尽量去避免这种异常,一旦发现该异常,正确的做法就会改进程序设计的代码和实现方式,修改程序中的错误,从而避免这种异常。捕获并处理运行时异常是好的解决办法,因为可以通过改进代码实现来避免该种异常的发生。对于受检查异常,没说的,老老实实去按照异常处理的方法去处理,要么用 try.catch 捕获并解决,要么用 throws 抛出!对于 Error(运行时错误),不需要在程序中做任何处理,出现问题后,应该在程序在外的

33、地方找问题,然后解决。六、异常转型和异常链异常转型在上面已经提到过了,实际上就是捕获到异常后,将异常以新的类型的异常再抛出,这样做一般为了异常的信息更直观!比如:public void run() throws MyException.try.catch(IOException e).throw new MyException();finally.异常链,在 JDK1.4 以后版本中,Throwable 类支持异常链机制。Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。最后,它还可以包含 cause(原因):另一个导致此 throwable 抛出的 throwable。它也称为异常链 设施,因为 cause 自身也

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 学术论文 > 毕业论文

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报