java多线程与异常处理_第1页
java多线程与异常处理_第2页
java多线程与异常处理_第3页
java多线程与异常处理_第4页
java多线程与异常处理_第5页
已阅读5页,还剩65页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、2022-5-16 15:4612022-5-16 15:46第 2 页v深入理解多线程的基本概念深入理解多线程的基本概念v熟练掌握创建线程的两种基本方法熟练掌握创建线程的两种基本方法v熟练处理线程的同步问题和死锁问题熟练处理线程的同步问题和死锁问题v深入理解异常的基本概念深入理解异常的基本概念v熟悉和掌握熟悉和掌握Java平台定义异常类平台定义异常类v熟练掌握创建自定义异常类的方法熟练掌握创建自定义异常类的方法v熟练运用异常处理的手段编写鲁棒的熟练运用异常处理的手段编写鲁棒的Java程程序序 本章学习要点本章学习要点2022-5-16 15:4632022-5-16 15:46第 4 页7.

2、1.1 7.1.1 多任务多任务v多任务多任务多任务是计算机操作系统同时运行几个程序或任务的能力。现代操作系统多任务是计算机操作系统同时运行几个程序或任务的能力。现代操作系统都支持多任务,多任务有两种形式:都支持多任务,多任务有两种形式:基于进程的多任务基于进程的多任务基于线程的多任务基于线程的多任务v程序、进程和线程程序、进程和线程程序程序是一段静态的代码,它是应用程序执行的蓝本。是一段静态的代码,它是应用程序执行的蓝本。进程进程是程序的一次动态执行过程,它对应了从代码加载、执行到执行完毕是程序的一次动态执行过程,它对应了从代码加载、执行到执行完毕的一个完整过程。程序可以被多次加载到系统的不

3、同内存区域分别执行,形的一个完整过程。程序可以被多次加载到系统的不同内存区域分别执行,形成不同的进程。成不同的进程。线程线程是进程内部的一个顺序执行控制流。是进程内部的一个顺序执行控制流。 一个进程在执行过程中,可以产一个进程在执行过程中,可以产生多个线程同时执行。每个线程也有自己产生、存在和消亡的过程。生多个线程同时执行。每个线程也有自己产生、存在和消亡的过程。http:/ 15:46第 5 页7.1.2 线程与多线程v线程和进程的区别:线程和进程的区别:从逻辑的观点来看,多线程意味着一个程序的多行语句同时从逻辑的观点来看,多线程意味着一个程序的多行语句同时执行,但是多线程并不等于多次启动一

4、个程序,操作系统也执行,但是多线程并不等于多次启动一个程序,操作系统也不会把每个线程当作独立的进程来对待。不会把每个线程当作独立的进程来对待。两者的层次不同,进程是由操作系统来管理的,而线程两者的层次不同,进程是由操作系统来管理的,而线程则是在一个程序则是在一个程序(进程进程)内部存在的。内部存在的。不同进程的代码、内部数据和状态都是完全独立的,进不同进程的代码、内部数据和状态都是完全独立的,进程之间进行切换和通信的开销很大。程之间进行切换和通信的开销很大。线程本身的数据通常只有寄存器数据,以及一个程序执线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,一个程序内的多个线程是共享

5、同一内行时使用的堆栈,一个程序内的多个线程是共享同一内存空间和系统资源,所以线程的切换比进程切换的开销存空间和系统资源,所以线程的切换比进程切换的开销要小,线程之间的通信很容易。要小,线程之间的通信很容易。2022-5-16 15:46第 6 页7.1.2 线程与多线程程序区段程序区段程序区段程序区段文件文件输入输出装置输入输出装置各种系统资源各种系统资源数据区段数据区段只有一个地方在执行只有一个地方在执行文件文件输入输出装置输入输出装置各种系统资源各种系统资源数据区段数据区段同时有数个地方在执行同时有数个地方在执行传统的进程传统的进程多线程的任务多线程的任务2022-5-16 15:46第

6、7 页7.1.3 Java7.1.3 Java对多线程的支持对多线程的支持 对多线程的综合支持是对多线程的综合支持是Java语言的一个重要特色,它提供了语言的一个重要特色,它提供了Thread类来实现多线程。在类来实现多线程。在Java中,线程可以认为是由三部中,线程可以认为是由三部分组成的:分组成的:虚拟虚拟CPU,封装在,封装在java.lang.Thread类中,它控制着整个类中,它控制着整个线程的运行;线程的运行;执行代码,传递给执行代码,传递给Thread类,由类,由Thread类控制顺序执行;类控制顺序执行;处理的数据,传递给处理的数据,传递给Thread类,是在代码执行过程中所类

7、,是在代码执行过程中所要处理的数据。要处理的数据。2022-5-16 15:46第 8 页7.1.4 7.1.4 线程的状态线程的状态v每个每个Java程序都有一个缺省的主线程,对于程序都有一个缺省的主线程,对于Application,主,主线程是线程是main()方法的执行线索;对于方法的执行线索;对于Applet,主线程是通过,主线程是通过浏览器加载并执行浏览器加载并执行Java小程序。小程序。v在一个线程的生命周期中,线程的状态表示了线程正在进行在一个线程的生命周期中,线程的状态表示了线程正在进行的活动以及在这段时间内线程能完成的任务。的活动以及在这段时间内线程能完成的任务。vJava使

8、用使用Thread类及其子类表示线程。新建的线程在它的类及其子类表示线程。新建的线程在它的一个完成生命周期中通常要经历五种状态。一个完成生命周期中通常要经历五种状态。新建新建(Newborn)就绪就绪(Runnable)运行运行(Running)阻塞阻塞(Blocked)死亡死亡(Dead)2022-5-16 15:46第 9 页7.1.4 7.1.4 线程的状态线程的状态新建新建死亡死亡运行运行就绪就绪阻塞阻塞s 线程的状态和生命周期线程的状态和生命周期2022-5-16 15:46第 10 页7.1.4 7.1.4 线程的状态线程的状态v新建状态新建状态(Newborn)当创建了一个新的线

9、程时,它就处于新建状态,此时它仅当创建了一个新的线程时,它就处于新建状态,此时它仅仅是一个空的线程对象,系统不为它分配资源。处于这种仅是一个空的线程对象,系统不为它分配资源。处于这种状态时只能启动状态时只能启动Start()或终止或终止Stop()该线程,调用除这两种该线程,调用除这两种以外的其它方法都会失败并且会引起非法状态异常以外的其它方法都会失败并且会引起非法状态异常IllegalThreadStateException(对于其它状态,若所调用的方对于其它状态,若所调用的方法与状态不符,都会引起非法状态异常法与状态不符,都会引起非法状态异常)。2022-5-16 15:46第 11 页7

10、.1.4 7.1.4 线程的状态线程的状态v就绪状态就绪状态(Runnable)当线程处于新建状态时,可以调用当线程处于新建状态时,可以调用start()方法来启动它,方法来启动它,产生运行这个线程所需的系统资源,安排其运行,并调用产生运行这个线程所需的系统资源,安排其运行,并调用线程体线程体run()方法,这样就使得该线程处于就绪方法,这样就使得该线程处于就绪( Runnable )状态。状态。需要注意的是这一状态并不是运行状态需要注意的是这一状态并不是运行状态(Running ),因为,因为线程也许实际上并未真正运行。由于很多计算机都是单处线程也许实际上并未真正运行。由于很多计算机都是单处

11、理器的,所以要在同一时刻运行所有的处于就绪状态的线理器的,所以要在同一时刻运行所有的处于就绪状态的线程是不可能的,程是不可能的,Java运行系统必须实现调度来保证这些线运行系统必须实现调度来保证这些线程共享处理器。但是在大多数情况下,可运行状态也就是程共享处理器。但是在大多数情况下,可运行状态也就是运行中,当一个线程正在运行时,它是可运行的,并且也运行中,当一个线程正在运行时,它是可运行的,并且也是当前正运行的线程。是当前正运行的线程。2022-5-16 15:46第 12 页Thread myThread = new MyThreadClass();Thread myThread = new

12、 MyThreadClass();myThread.start();myThread.start();trytry myThread.sleep(10000); myThread.sleep(10000); catch (InterruptedException e) catch (InterruptedException e) 7.1.4 7.1.4 线程的状态线程的状态v阻塞状态阻塞状态(Blocked)线程处于可运行状态时,当下面四种情况发生,线程就进线程处于可运行状态时,当下面四种情况发生,线程就进入不可运行状态:入不可运行状态: 调用了休眠方法调用了休眠方法sleep( )或或yie

13、ld() 方法;方法; 调用了挂起方法调用了挂起方法suspend( ); 为等候一个条件变量,线程调用等待方法为等候一个条件变量,线程调用等待方法wait(); 输入输出流中发生线程阻塞。输入输出流中发生线程阻塞。2022-5-16 15:46第 13 页7.1.4 7.1.4 线程的状态线程的状态v阻塞状态阻塞状态(Blocked) 对于这四种使得线程处于不可运行状态的情况,都有特定的对于这四种使得线程处于不可运行状态的情况,都有特定的方法使线程返回可运行状态:方法使线程返回可运行状态:如果线程处于休眠状态中,如果线程处于休眠状态中,sleep()方法中的参数为休眠时方法中的参数为休眠时间

14、,当这个时间过去后,线程即为可运行的;间,当这个时间过去后,线程即为可运行的;如果线程在等待条件变量,那么要停止等待的话,需要如果线程在等待条件变量,那么要停止等待的话,需要该条件变量所在的对象调用该条件变量所在的对象调用notify()或或notifyAll()方法方法;如果在如果在I/O流中发生线程阻塞,则特定的流中发生线程阻塞,则特定的I/O指令将结束这指令将结束这种不可运行状态。种不可运行状态。 需要注意的是每种方法都仅仅对相应的情况才有作用,例如需要注意的是每种方法都仅仅对相应的情况才有作用,例如当一个线程休眠并且休眠时间还没有结束时,调用其他方法当一个线程休眠并且休眠时间还没有结束

15、时,调用其他方法是无效的,并且还会引起非法状态异常。是无效的,并且还会引起非法状态异常。2022-5-16 15:46第 14 页7.1.4 7.1.4 线程的状态线程的状态v死亡状态死亡状态(Dead)线程的终止一般可通过两种方法实现:自然撤消或是被停线程的终止一般可通过两种方法实现:自然撤消或是被停止。止。自然撤消是指从线程的自然撤消是指从线程的run( )方法正常结束退出,如果希方法正常结束退出,如果希望线程正常终止,一般可设置标记来使线程中的望线程正常终止,一般可设置标记来使线程中的run()方法方法退出。退出。调用线程的实例方法调用线程的实例方法stop( )则可以强制停止当前线程。

16、既则可以强制停止当前线程。既可以通过在其他线程中调用可以通过在其他线程中调用stop()方法来终止线程,也可以方法来终止线程,也可以由线程自己调用由线程自己调用stop()方法,自我终止。但这个方法已在方法,自我终止。但这个方法已在JDK2中建议不再使用,应当避免使用。中建议不再使用,应当避免使用。 2022-5-16 15:46第 15 页7.1.5 7.1.5 线程的优先级线程的优先级 v处在处在就绪状态就绪状态下的线程,可能有多个,它们各自任务的重要下的线程,可能有多个,它们各自任务的重要程度不同。程度不同。vJava提供一个线程调度器来监控程序中启动后进入就绪状态提供一个线程调度器来监

17、控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定调度哪些线的所有线程。线程调度器按照线程的优先级决定调度哪些线程来执行。程来执行。多个线程运行时,具有高优先级的线程会在较低优先级多个线程运行时,具有高优先级的线程会在较低优先级的线程之前得到执行。的线程之前得到执行。同一优先级的线程,采取先进先出的原则由操作系统按同一优先级的线程,采取先进先出的原则由操作系统按时间片轮转方式或独占方式来分配线程的执行时间。时间片轮转方式或独占方式来分配线程的执行时间。同时线程的调度是抢先式的,即如果当前线程在执行过同时线程的调度是抢先式的,即如果当前线程在执行过程中,一个具有更高优先级的线程

18、进入可执行状态,则程中,一个具有更高优先级的线程进入可执行状态,则该高优先级的线程会被立即调度执行。该高优先级的线程会被立即调度执行。2022-5-16 15:46第 16 页7.1.5 7.1.5 线程的优先级线程的优先级 v线程的优先级用数字来表示,范围从线程的优先级用数字来表示,范围从1到到10,Thread类类有三个关于优先级的静态常量:有三个关于优先级的静态常量:MIN_PRIORITY=1MAX_ PRIORITY=10NORM_ PRIORITY=5v对应于一个新线程,系统会遵循以下原则:对应于一个新线程,系统会遵循以下原则:新线程将继承创建它的父线程的优先级。新线程将继承创建它

19、的父线程的优先级。一般情况下,线程具有普通优先级。一般情况下,线程具有普通优先级。用户可以根据需要,通过用户可以根据需要,通过setPriority()方法来修改优方法来修改优先级。先级。2022-5-16 15:46第 17 页7.2 线程的使用方法vJava中编程实现多线程有两种方式:中编程实现多线程有两种方式:由由Thread类派生子类创建线程类;类派生子类创建线程类;通过实现通过实现Runnable接口创建线程类。接口创建线程类。两种方法都要使用到两种方法都要使用到Java.lang中的中的Thread类及其方法来实类及其方法来实现。当生成一个现。当生成一个Thread对象之后,就产生

20、了一个线程,通对象之后,就产生了一个线程,通过该对象,可以启动线程、终止线程、或者暂时休眠等。过该对象,可以启动线程、终止线程、或者暂时休眠等。vThread类本身只是线程的虚拟类本身只是线程的虚拟CPU,线程所执行的代码,线程所执行的代码(或或者说线程所要完成的功能者说线程所要完成的功能)是通过方法是通过方法run()(包含在一个特定包含在一个特定的对象中的对象中)来完成的,方法来完成的,方法run()称为称为线程体线程体。实现线程体的。实现线程体的特定对象是在初始化线程时传递给线程的。在一个线程被建特定对象是在初始化线程时传递给线程的。在一个线程被建立并初始化以后,立并初始化以后,Java

21、的运行时系统就自动调用的运行时系统就自动调用run( )方法,方法,正是通过正是通过run( )方法才使得建立线程的目的得以实现。方法才使得建立线程的目的得以实现。2022-5-16 15:46第 18 页7.2.1 7.2.1 通过继承通过继承ThreadThread类构造线程类构造线程vTread类类v定义一个线程类,它继承类定义一个线程类,它继承类Thread,并重写其中的并重写其中的run( )方法。方法。这时在初始化这个类的实例时,目标对象这时在初始化这个类的实例时,目标对象target可以为可以为null,表示这个实例本身具有线程体。由于表示这个实例本身具有线程体。由于Java只支

22、持单继承,用只支持单继承,用这种方法定义的类不能再继承其他类。这种方法定义的类不能再继承其他类。vTread类综合了类综合了Java程序中一个线程所需要拥有的属性和方程序中一个线程所需要拥有的属性和方法,主要有:法,主要有:构造方法构造方法线程优先级线程优先级其他一些主要方法。其他一些主要方法。2022-5-16 15:46第 19 页7.2.1 7.2.1 通过继承通过继承ThreadThread类构造线程类构造线程vThread类的构造方法如下:类的构造方法如下:public Thread( ThreadGroup group, Runnable target, String name)

23、group指明了线程所属的线程组;指明了线程所属的线程组; target是线程体是线程体run()方法所在的对象;方法所在的对象; name是线程的名称。是线程的名称。vtarget必须实现接口必须实现接口Runnable。在接口。在接口Runnable中只定义了中只定义了一个方法一个方法void run()作为线程体。任何实现接口作为线程体。任何实现接口Runnable的的对象都可以作为一个线程的目标对象。对象都可以作为一个线程的目标对象。vstart()方法方法:启动线程,使线程由新建状态转为就绪状态;:启动线程,使线程由新建状态转为就绪状态;vrun()方法:方法:定义该线程的操作;定义

24、该线程的操作;2022-5-16 15:46第 20 页7.2.1 7.2.1 通过继承通过继承ThreadThread类构造线程类构造线程vsleep()方法:方法:使线程进入到休眠状态。让其它线程得到机会使线程进入到休眠状态。让其它线程得到机会执行。执行。sleep()会抛出异常会抛出异常InterruptedException ,必须捕获。,必须捕获。v isAlive()方法:方法:可以用来判断线程目前是否正在执行状态中。可以用来判断线程目前是否正在执行状态中。如果线程已被启动并且未被终止,那么如果线程已被启动并且未被终止,那么isAlive( )返回返回true,但,但该线程是可运行

25、或是不可运行的,是不能作进一步的分辨。该线程是可运行或是不可运行的,是不能作进一步的分辨。如果返回如果返回false,则该线程是新创建或是已被终止的,则该线程是新创建或是已被终止的(同样不能同样不能作进一步的分辨作进一步的分辨)。v join()方法:方法:等待线程终止。等待线程终止。v yield()方法方法:将执行的权力交给其它优先级相同的线程,自:将执行的权力交给其它优先级相同的线程,自己到可运行线程队列的最后等待,若队列空,该方法无效。己到可运行线程队列的最后等待,若队列空,该方法无效。2022-5-16 15:46第 21 页7.2.1 7.2.1 通过继承通过继承ThreadThr

26、ead类构造线程类构造线程v1. 线程的创建与启动线程的创建与启动v要创建并执行一个线程,须完成下列步骤:要创建并执行一个线程,须完成下列步骤:v(1)创建一个类扩展)创建一个类扩展Thread类。类。v(2)用要在这个线程中执行的代码覆盖)用要在这个线程中执行的代码覆盖Thread类的类的run()方方法。法。v(3)用关键字)用关键字new创建所定义的线程类的一个对象。创建所定义的线程类的一个对象。v(4)调用该对象的)调用该对象的start()方法启动线程。方法启动线程。v【例例7.1】 创建一个创建一个Thread类的子类,显示类的子类,显示18这这8个数字,个数字,然后在另一个类中建

27、立这个然后在另一个类中建立这个Thread类的类的3个对象来测试它,个对象来测试它,看执行时会发生什么现象。看执行时会发生什么现象。2022-5-16 15:46第 22 页7.2.1 7.2.1 通过继承通过继承ThreadThread类构造线程类构造线程v使用线程的一些技巧使用线程的一些技巧v如下步骤实现一种简单的机制,可在任何时候终止线程。如下步骤实现一种简单的机制,可在任何时候终止线程。v 编写一个类扩展编写一个类扩展Thread类。类。v 增加一个布尔变量增加一个布尔变量running到这个类中,并初始化为到这个类中,并初始化为false。v 覆盖覆盖start()方法,置方法,置r

28、unning为为true,然后调用,然后调用super.start()。v 提供一个提供一个public方法方法halt(),它将,它将running变量置为变量置为false。v 在在run()方法中使用类似于下例的方法中使用类似于下例的while循环:循环:public void run() while (running) /* 线程要执行的代码线程要执行的代码 */ v如果如果halt()方法被调用,就会引起方法被调用,就会引起run()方法终止执行,结束方法终止执行,结束该线程。该线程。 2022-5-16 15:46第 23 页7.2.1 7.2.1 通过继承通过继承ThreadTh

29、read类构造线程类构造线程v【例例7.2】 模拟一个笼子内有二十个鸟在里面移动,每个模拟一个笼子内有二十个鸟在里面移动,每个“鸟鸟”是一个是一个Thread类。类。“笼子笼子”是扩展是扩展Frame的类。它包的类。它包含有含有3个按钮,用于启动、终止个按钮,用于启动、终止“鸟鸟”和退出程序。和退出程序。“鸟鸟”在碰到在碰到“笼子笼子”的边缘时应返回来,这样就不会离开笼子。的边缘时应返回来,这样就不会离开笼子。v“鸟鸟”类可按如下步骤去实现类可按如下步骤去实现:v 这个类扩展这个类扩展Thread,这样就可独立执行自己的线程。,这样就可独立执行自己的线程。v 按上述线程设计的技巧,使得鸟类可在

30、任何时刻停止执行。按上述线程设计的技巧,使得鸟类可在任何时刻停止执行。v 设置两个域设置两个域x,y,作为鸟的当前坐标。,作为鸟的当前坐标。v 为了重新移动鸟到一个新的为了重新移动鸟到一个新的x,y坐标,在方法中重新计算坐标,在方法中重新计算它的坐标,使它产生移动效果。它的坐标,使它产生移动效果。v 由于有多个移动的鸟,所以在每个线程的由于有多个移动的鸟,所以在每个线程的run()方法中应该方法中应该调用调用sleep()方法,这样就可以让出时间使操作系统去移动其方法,这样就可以让出时间使操作系统去移动其他的鸟。他的鸟。2022-5-16 15:46第 24 页7.2.1 7.2.1 通过继承

31、通过继承ThreadThread类构造线程类构造线程v【扩展海底世界扩展海底世界】 模拟多条鱼在海底游动,每个模拟多条鱼在海底游动,每个“鱼鱼”是一个是一个Thread类。类。“海底海底”是扩展是扩展Frame的类,的类,Frame内粘内粘贴一副精美的海底画面。在前面的例子中去掉按钮,用鼠标贴一副精美的海底画面。在前面的例子中去掉按钮,用鼠标的双击来启动、终止的双击来启动、终止“鱼鱼”的游动。的游动。2022-5-16 15:46第 25 页7.2.2 通过实现Runnable接口来构造线程vRunnable接口接口vRunnable接口只有一个方法接口只有一个方法run(),所有实现所有实现

32、Runnabel接口的接口的用户类都必须具体实现这个用户类都必须具体实现这个run()方法,为它编写具体的方方法,为它编写具体的方法体代码并定义实现的操作。法体代码并定义实现的操作。v run()方法比较特殊,它可以被系统自动识别并执行。方法比较特殊,它可以被系统自动识别并执行。v多线程应用的实质就是在主线程之外,定义了一个或多个新多线程应用的实质就是在主线程之外,定义了一个或多个新的线程。的线程。v在许多情况下,一个类已经扩展了在许多情况下,一个类已经扩展了Frame或或Applet,由于单,由于单继承性,这样的类就不能再继承继承性,这样的类就不能再继承Thread。Runnable接口为接

33、口为一个类提供了一种手段,无须扩展一个类提供了一种手段,无须扩展Thread类就可以创建一个类就可以创建一个新的线程。从而克服了单一继承方式所造成的限制。新的线程。从而克服了单一继承方式所造成的限制。2022-5-16 15:46第 26 页7.2.2 通过实现Runnable接口来构造线程v所有实现了所有实现了Runnable接口的类的对象都能以线程方式执行。接口的类的对象都能以线程方式执行。使用使用Runnable接口构造线程要在一个类中实现接口构造线程要在一个类中实现public void run()方法,并建立一个方法,并建立一个Thread类型的域。实现类型的域。实现Runnable

34、接接口的类的一般框架为:口的类的一般框架为:vmodifier class ClassName extends SuperClassName v implements Runnable , OtherInterfaceListv / 域,构造方法和其他方法域,构造方法和其他方法v Thread threadobj;v SomeMethodv threadobj = new Thread(this);v v public void run()v /* run方法的代码方法的代码 */v 2022-5-16 15:46第 27 页7.2.2 通过实现Runnable接口来构造线程v【例例7.3】

35、创建一个程序,用实现创建一个程序,用实现Runnable接口的方法来完接口的方法来完成每秒显示当前时间。成每秒显示当前时间。v在在Java的的java.util包中有一个包中有一个Date类,实例化一个新的类,实例化一个新的Date对象可得到当前时间,再用对象可得到当前时间,再用toString()方法可将其变成字符串。方法可将其变成字符串。v下面要确定是否需要一个线程来完成这个任务。如果需要,下面要确定是否需要一个线程来完成这个任务。如果需要,要考虑是需要扩展要考虑是需要扩展Thread类还是使用类还是使用Runnable接口。接口。v要求每秒显示一次时间,线程是完成这个任务最好的角色。要求

36、每秒显示一次时间,线程是完成这个任务最好的角色。我们可以每秒唤醒一次线程,并且就在这一瞬间显示出时间,我们可以每秒唤醒一次线程,并且就在这一瞬间显示出时间,这只要在这只要在run()方法中调用方法中调用System.out.println()就可以完成。就可以完成。v假如这个时钟要以窗口的形式出现,则这个线程必须选择使假如这个时钟要以窗口的形式出现,则这个线程必须选择使用用Runnable接口来实现。接口来实现。2022-5-16 15:46第 28 页两种创建线程方式的比较两种创建线程方式的比较v使用使用Runnable接口接口可以将虚拟可以将虚拟CPU,代码和数据分开,形成清晰的模型,代码

37、和数据分开,形成清晰的模型;还可以类继承其他还可以类继承其他;保持程序风格的一致性。保持程序风格的一致性。v继承继承Thread类类不能再从其他类继承不能再从其他类继承;编写简单,可以直接操纵线程,无需使用编写简单,可以直接操纵线程,无需使用Thread.currentThread( ) 。无论采取上述的哪种方式,程序员可控制的关键操作有两个:无论采取上述的哪种方式,程序员可控制的关键操作有两个:定义用户线程的操作,即定义用户线程的定义用户线程的操作,即定义用户线程的run()方法;方法;在适当的时候建立用户线程实例。在适当的时候建立用户线程实例。2022-5-16 15:46第 29 页7.

38、3 7.3 线程的同步线程的同步v线程间的资源互斥共享线程间的资源互斥共享 通常,一些同时运行的线程需要共享数据。在这种时候,每通常,一些同时运行的线程需要共享数据。在这种时候,每个线程就必须要考虑其它与它一起共享数据的线程的状态与个线程就必须要考虑其它与它一起共享数据的线程的状态与行为,否则的话就不能保证共享数据的一致性,从而也就不行为,否则的话就不能保证共享数据的一致性,从而也就不能保证程序的正确性。能保证程序的正确性。v在在Java语言中,引入了语言中,引入了“对象互斥锁对象互斥锁”的概念的概念(又称为监视又称为监视器、管程器、管程)来实现不同线程对共享数据操作的同步。来实现不同线程对共

39、享数据操作的同步。 “对象对象互斥锁互斥锁”阻止多个线程同时访问同一个条件变量。阻止多个线程同时访问同一个条件变量。v在在Java语言中,有两种方法可以实现语言中,有两种方法可以实现“对象互斥锁对象互斥锁”: 用关键字用关键字volatile来声明一个共享数据来声明一个共享数据(变量变量); 用关键字用关键字synchronized来声明一个操作共享数据的方法或来声明一个操作共享数据的方法或一段代码。一段代码。2022-5-16 15:46第 30 页7.3 7.3 线程的同步线程的同步v 线程间的同步线程间的同步 除了要处理多线程间共享数据操作的同步问题之外,在进行除了要处理多线程间共享数据

40、操作的同步问题之外,在进行多线程程序设计时,还会遇到另一类问题,这就是如何控制多线程程序设计时,还会遇到另一类问题,这就是如何控制相互交互的线程之间的运行进度,即多线程的同步。相互交互的线程之间的运行进度,即多线程的同步。v典型的模型:生产者典型的模型:生产者消费者问题消费者问题若共享对象中只能存放一个数据,可能出现以下问题若共享对象中只能存放一个数据,可能出现以下问题: 生产者比消费者快时,消费者会漏掉一些数据没有取到;生产者比消费者快时,消费者会漏掉一些数据没有取到; 消费者比生产者快时,消费者取相同的数据。消费者比生产者快时,消费者取相同的数据。生产者生产者消费者消费者共享对象共享对象p

41、utget2022-5-16 15:46第 31 页7.3.1 使用多线程不当造成的数据崩溃v多线程使用不当,则有可能造成数据崩溃。例如,两个线程多线程使用不当,则有可能造成数据崩溃。例如,两个线程都要访问同一个整数域,一个线程读取这个域的值并在这个都要访问同一个整数域,一个线程读取这个域的值并在这个值的基础上完成某些操作,而另一个线程改变了这个整数值,值的基础上完成某些操作,而另一个线程改变了这个整数值,但第一个线程并不知道,这就可能造成数据崩溃。但第一个线程并不知道,这就可能造成数据崩溃。慢线程慢线程快线程快线程资源资源取过来显示取过来显示随机产生随机产生number变量变量修改成修改成-

42、12022-5-16 15:46第 32 页7.3.1 使用多线程不当造成的数据崩溃v【例例7.4】 创建一个类,它包含一个具有随机值的域创建一个类,它包含一个具有随机值的域number和一个和一个performWork()方法,该方法完成两个任务:方法,该方法完成两个任务:一个一个“慢慢”任务和一个任务和一个“快快”任务。完成这些任务并不是直任务。完成这些任务并不是直接调用这个方法,而是建立两个线程对象:一个快线程,一接调用这个方法,而是建立两个线程对象:一个快线程,一个慢线程。个慢线程。v “慢慢”线程调用线程调用performwork并显示一个随机数,然后让这并显示一个随机数,然后让这个

43、线程休眠个线程休眠2秒钟,以模拟一个需要较长时间才能完成的任秒钟,以模拟一个需要较长时间才能完成的任务,最后再次显示这个务,最后再次显示这个number。v “快快”线程在线程在performwork中将中将number修改为修改为-1,该线程没,该线程没用延时,以模拟一个能够很快完成的任务。用延时,以模拟一个能够很快完成的任务。2022-5-16 15:46第 33 页7.3.1 使用多线程不当造成的数据崩溃v【例例7.5】 建立一个银行(建立一个银行(Bank)类,它包含)类,它包含8个储蓄账号。个储蓄账号。每个账号最初有每个账号最初有10万元余额。万元余额。Bank类包含一个转账的类包含

44、一个转账的transfer方法,可以将钱从一个储蓄账号转到其他账号。从方法,可以将钱从一个储蓄账号转到其他账号。从储蓄账户取钱再打到其他账户应该是要花费一定时间的操作。储蓄账户取钱再打到其他账户应该是要花费一定时间的操作。vBank类还有一个类还有一个showAccounts()方法显示所有的账户的总金方法显示所有的账户的总金额。额。 Bank类创建类创建8个线程对象模拟八个客户。个线程对象模拟八个客户。v这些储户线程使用这些储户线程使用Bank的的transfer()方法不断从他们的账号方法不断从他们的账号中转出一定数目(随机数目,但不超过中转出一定数目(随机数目,但不超过1000元)的钱到

45、其他元)的钱到其他随机选定的账号。随机选定的账号。transfer()方法需要方法需要3个输入参数:从中取个输入参数:从中取钱的账号,存钱的账号,转账的金额。钱的账号,存钱的账号,转账的金额。v这个程序在一个这个程序在一个Frame中执行,并设置按钮来重新进行计算中执行,并设置按钮来重新进行计算和显示各账号的储蓄总额。和显示各账号的储蓄总额。2022-5-16 15:46第 34 页7.3.2 7.3.2 同步线程同步线程v为了解决所出现的问题,为了解决所出现的问题,Java提供了线程的同步用于保护线提供了线程的同步用于保护线程共享数据,控制和切换线程的执行,保证内存的一致性,程共享数据,控制

46、和切换线程的执行,保证内存的一致性,v声明声明synchronized()方法的一般格式为:方法的一般格式为:modifier synchronized returnType methodName(parameterList) /* 方法体方法体 */ vsynchronized关键字除了可以放在方法声明中表示整个方法为关键字除了可以放在方法声明中表示整个方法为同步方法外,还可以放在一段代码的前面限制它的执行,如:同步方法外,还可以放在一段代码的前面限制它的执行,如:vmodifier returnType methodName(parameterList)v synchronized(thi

47、s) /* some codes */ v另外,如果另外,如果synchronized用在类声明中,则表明该类中的所有用在类声明中,则表明该类中的所有方法都是方法都是synchronized的。的。 2022-5-16 15:46第 35 页7.3.2 7.3.2 同步线程同步线程v在在Java语言中还可以用语言中还可以用wait () 和和notify( )/notifyAll( )方法用方法用来协调线程间的读取关系。来协调线程间的读取关系。 wait( )方法的作用是让当前线程释放其所持有的方法的作用是让当前线程释放其所持有的“对象互对象互斥锁斥锁”,进入,进入wait队列队列(等待队列等

48、待队列);notify( )/notifyAll( )方法的作用是唤醒一个或所有正在等方法的作用是唤醒一个或所有正在等待队列中等待的线程,并将它待队列中等待的线程,并将它(们们)移入等待同一个移入等待同一个“对象对象互斥锁互斥锁”的队列。的队列。v需要指出的是:需要指出的是: notify()/notifyAll()方法和方法和wait ()方法都只能方法都只能在被声明为在被声明为synchronized的方法或代码段中调用。的方法或代码段中调用。v例例7.6v例例7.72022-5-16 15:46362022-5-16 15:46第 37 页异常的概念异常的概念v在进行程序设计时,错误的产

49、生是不可避免的,如何处理错在进行程序设计时,错误的产生是不可避免的,如何处理错误?把错误交给谁去处理?程序又该如何从错误中恢复?这误?把错误交给谁去处理?程序又该如何从错误中恢复?这是任何程序设计语言都要解决的问题。是任何程序设计语言都要解决的问题。v程序运行过程中会发生一些异常事件,比如除程序运行过程中会发生一些异常事件,比如除0溢出、数组溢出、数组越界、文件找不到等,这些事件的发生将阻止程序的正常运越界、文件找不到等,这些事件的发生将阻止程序的正常运行。行。v在在C语言中,通过使用语言中,通过使用if语句来判断是否出现了错误,同时,语句来判断是否出现了错误,同时,调用函数通过被调用函数的返

50、回值感知在被调用函数中产生调用函数通过被调用函数的返回值感知在被调用函数中产生的错误事件并进行处理。但是,这种错误处理机制会导致不的错误事件并进行处理。但是,这种错误处理机制会导致不少问题。通常,用全局变量少问题。通常,用全局变量Errno来存储一个异常事件的类来存储一个异常事件的类型,这容易导致误用,因为一个型,这容易导致误用,因为一个Errno的值有可能在被处理的值有可能在被处理前被另外的错误覆盖掉。此外,即使最优美的前被另外的错误覆盖掉。此外,即使最优美的C语言程序,语言程序,为了处理异常情况,也常常求助于为了处理异常情况,也常常求助于goto语句。语句。2022-5-16 15:46第

51、 38 页异常的概念异常的概念 没有进行错误处理的程序没有进行错误处理的程序: openTheFile; determine its size; allocate that much memory; read-file closeTheFile; 以常规方法进行错误处理:以常规方法进行错误处理:openFiles;if (theFilesOpen) determine the length of the file; if (gotTheFileLength) allocate that much memory; if (gotEnoughMemory) read the file into m

52、emory; if (readFailed) errorCode=-1; else errorCode = -2; else errorCode=-3; else errorCode=-4 ;else errorCode=-5; v 观察这个程序,会发现大观察这个程序,会发现大部分精力花在出错处理上部分精力花在出错处理上v 只能考虑到部分错误,对只能考虑到部分错误,对其它的情况无法处理其它的情况无法处理v 程序可读性差程序可读性差v 出错返回信息量太少出错返回信息量太少2022-5-16 15:46第 39 页异常的概念异常的概念vJava通过面向对象的方法来处理程序错误,在通过面向对象的方法

53、来处理程序错误,在Java中,错误中,错误被称为异常被称为异常(Exception)。v在一个方法的运行过程中,如果发生了异常,则这个方法在一个方法的运行过程中,如果发生了异常,则这个方法(或者是或者是Java虚拟机虚拟机)生成一个代表该异常的对象生成一个代表该异常的对象(包含了该异包含了该异常的详细信息常的详细信息),并把它交给运行时系统,运行时系统寻找,并把它交给运行时系统,运行时系统寻找相应的代码来处理这一异常。我们把生成异常对象并把它提相应的代码来处理这一异常。我们把生成异常对象并把它提交给运行时系统的过程称为抛出交给运行时系统的过程称为抛出(throw)一个异常。一个异常。v运行时系

54、统在方法的调用栈中查找,从生成异常的方法开始运行时系统在方法的调用栈中查找,从生成异常的方法开始进行回朔,直到找到包含相应异常处理的方法为止,这一个进行回朔,直到找到包含相应异常处理的方法为止,这一个过程称为捕获过程称为捕获(catch)一个异常。一个异常。2022-5-16 15:46第 40 页 异常的概念异常的概念用异常的形式处理错误:用异常的形式处理错误:try openTheFile; determine its size; allocate that much memory; read-File; closeTheFile; catch(fileopenFailed) dosome

55、thing; catch(sizeDetermineFailed) dosomething; catch(memoryAllocateFailed) dosomething; catch(readFailed) dosomething; catch(fileCloseFailed) dosomething; 2022-5-16 15:46第 41 页method1method2method3method4产生异常传 递处理异常调 用 异常的概念异常的概念v与传统的方法比较,异常的优点包括与传统的方法比较,异常的优点包括:1.把错误处理代码从常规代码中分离出来把错误处理代码从常规代码中分离出来2

56、. 把错误传送给调用堆栈把错误传送给调用堆栈3. 按错误类型和错误差别分组按错误类型和错误差别分组4. 系统提供了对于一些无法预测的错误的捕获和处理系统提供了对于一些无法预测的错误的捕获和处理5. 克服了传统方法的错误信息有限的问题克服了传统方法的错误信息有限的问题2022-5-16 15:46第 42 页7.4.1 Java的出错类型v一个异常是由一个对象来代表的一个异常是由一个对象来代表的,所有的异常都直所有的异常都直接或间接地继承自接或间接地继承自Throwable类。类。v在在Java类库的每个类包中都定义了异常类,这些异类库的每个类包中都定义了异常类,这些异常类分成两大类:常类分成两

57、大类:Error类及类及Exception类,后者是类,后者是Java程序中需要大量处理的。程序中需要大量处理的。v除了除了Java类库所定义的异常类之外,用户也可以通类库所定义的异常类之外,用户也可以通过继承已有的异常类来定义自己的异常类,并在程过继承已有的异常类来定义自己的异常类,并在程序中使用序中使用(利用利用throw抛出异常,用抛出异常,用catch捕捉异常捕捉异常)。2022-5-16 15:46第 43 页ThrowableErrorExceptionExceptionRuntimeException缺省的异常缺省的异常处理程序处理程序由用户捕获或由用户捕获或声明并处理声明并处理

58、不做处理不做处理用户自己定义的异常用户自己定义的异常处理处理7.4.1 Java的出错类型2022-5-16 15:46第 44 页7.4.1 Java的出错类型vError:由:由Java虚拟机生成并抛出,包括动态链接失败、虚虚拟机生成并抛出,包括动态链接失败、虚拟机错误等,拟机错误等,Java程序不做处理。程序不做处理。vRuntime Exception:Java虚拟机在运行时生成的异常,如虚拟机在运行时生成的异常,如被被0除等系统错误、数组下标超范围等,其产生比较频繁,除等系统错误、数组下标超范围等,其产生比较频繁,处理麻烦,对程序可读性和运行效率影响太大。因此由系统处理麻烦,对程序可

59、读性和运行效率影响太大。因此由系统检测检测, 用户可不做处理,系统将它们交给缺省的异常处理程用户可不做处理,系统将它们交给缺省的异常处理程序序(当然,必要时,用户可对其处理当然,必要时,用户可对其处理)。vException:一般程序中可预知的问题,其产生的异常可能:一般程序中可预知的问题,其产生的异常可能会带来意想不到的结果,因此会带来意想不到的结果,因此Java编译器要求编译器要求Java程序必须程序必须捕获或声明所有的非运行时异常。捕获或声明所有的非运行时异常。v用户自己产生的异常用户自己产生的异常2022-5-16 15:46第 45 页7.4.2 异常类的定义v 常见的系统定义的异常

60、常见的系统定义的异常 ArithmeticException ArrayIndexOutOfBandsException ArrayStoreException IOException FileNotFoundException NullPointerException MalformedURLException NumberFormatException OutOfMemoryException 在使用能够产生异常的方法而没有捕获和处理,程序将不能在使用能够产生异常的方法而没有捕获和处理,程序将不能通过编译。通过编译。 例例7.92022-5-16 15:46第 46 页7.4.2 异常类的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论