您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 人事档案/员工关系 > java多线程与异常处理.
2020/1/1022:031第七章多线程与异常处理武汉大学计算机学院计算机应用系2020/1/1022:03第2页深入理解多线程的基本概念熟练掌握创建线程的两种基本方法熟练处理线程的同步问题和死锁问题深入理解异常的基本概念熟悉和掌握Java平台定义异常类熟练掌握创建自定义异常类的方法熟练运用异常处理的手段编写鲁棒的Java程序本章学习要点2020/1/1022:0337.1多线程的基本概念2020/1/1022:03第4页7.1.1多任务多任务多任务是计算机操作系统同时运行几个程序或任务的能力。现代操作系统都支持多任务,多任务有两种形式:基于进程的多任务基于线程的多任务程序、进程和线程程序是一段静态的代码,它是应用程序执行的蓝本。进程是程序的一次动态执行过程,它对应了从代码加载、执行到执行完毕的一个完整过程。程序可以被多次加载到系统的不同内存区域分别执行,形成不同的进程。线程是进程内部的一个顺序执行控制流。一个进程在执行过程中,可以产生多个线程同时执行。每个线程也有自己产生、存在和消亡的过程。:03第5页7.1.2线程与多线程线程和进程的区别:从逻辑的观点来看,多线程意味着一个程序的多行语句同时执行,但是多线程并不等于多次启动一个程序,操作系统也不会把每个线程当作独立的进程来对待。两者的层次不同,进程是由操作系统来管理的,而线程则是在一个程序(进程)内部存在的。不同进程的代码、内部数据和状态都是完全独立的,进程之间进行切换和通信的开销很大。线程本身的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,一个程序内的多个线程是共享同一内存空间和系统资源,所以线程的切换比进程切换的开销要小,线程之间的通信很容易。2020/1/1022:03第6页7.1.2线程与多线程程序区段程序区段文件输入输出装置各种系统资源数据区段只有一个地方在执行文件输入输出装置各种系统资源数据区段同时有数个地方在执行传统的进程多线程的任务2020/1/1022:03第7页7.1.3Java对多线程的支持对多线程的综合支持是Java语言的一个重要特色,它提供了Thread类来实现多线程。在Java中,线程可以认为是由三部分组成的:虚拟CPU,封装在java.lang.Thread类中,它控制着整个线程的运行;执行代码,传递给Thread类,由Thread类控制顺序执行;处理的数据,传递给Thread类,是在代码执行过程中所要处理的数据。2020/1/1022:03第8页7.1.4线程的状态每个Java程序都有一个缺省的主线程,对于Application,主线程是main()方法的执行线索;对于Applet,主线程是通过浏览器加载并执行Java小程序。在一个线程的生命周期中,线程的状态表示了线程正在进行的活动以及在这段时间内线程能完成的任务。Java使用Thread类及其子类表示线程。新建的线程在它的一个完成生命周期中通常要经历五种状态。新建(Newborn)就绪(Runnable)运行(Running)阻塞(Blocked)死亡(Dead)2020/1/1022:03第9页7.1.4线程的状态新建死亡运行就绪阻塞线程的状态和生命周期2020/1/1022:03第10页7.1.4线程的状态新建状态(Newborn)当创建了一个新的线程时,它就处于新建状态,此时它仅仅是一个空的线程对象,系统不为它分配资源。处于这种状态时只能启动Start()或终止Stop()该线程,调用除这两种以外的其它方法都会失败并且会引起非法状态异常IllegalThreadStateException(对于其它状态,若所调用的方法与状态不符,都会引起非法状态异常)。2020/1/1022:03第11页7.1.4线程的状态就绪状态(Runnable)当线程处于新建状态时,可以调用start()方法来启动它,产生运行这个线程所需的系统资源,安排其运行,并调用线程体run()方法,这样就使得该线程处于就绪(Runnable)状态。需要注意的是这一状态并不是运行状态(Running),因为线程也许实际上并未真正运行。由于很多计算机都是单处理器的,所以要在同一时刻运行所有的处于就绪状态的线程是不可能的,Java运行系统必须实现调度来保证这些线程共享处理器。但是在大多数情况下,可运行状态也就是运行中,当一个线程正在运行时,它是可运行的,并且也是当前正运行的线程。2020/1/1022:03第12页ThreadmyThread=newMyThreadClass();myThread.start();try{myThread.sleep(10000);}catch(InterruptedExceptione){}7.1.4线程的状态阻塞状态(Blocked)线程处于可运行状态时,当下面四种情况发生,线程就进入不可运行状态:调用了休眠方法sleep()或yield()方法;调用了挂起方法suspend();为等候一个条件变量,线程调用等待方法wait();输入输出流中发生线程阻塞。2020/1/1022:03第13页7.1.4线程的状态阻塞状态(Blocked)对于这四种使得线程处于不可运行状态的情况,都有特定的方法使线程返回可运行状态:如果线程处于休眠状态中,sleep()方法中的参数为休眠时间,当这个时间过去后,线程即为可运行的;如果线程在等待条件变量,那么要停止等待的话,需要该条件变量所在的对象调用notify()或notifyAll()方法;如果在I/O流中发生线程阻塞,则特定的I/O指令将结束这种不可运行状态。需要注意的是每种方法都仅仅对相应的情况才有作用,例如当一个线程休眠并且休眠时间还没有结束时,调用其他方法是无效的,并且还会引起非法状态异常。2020/1/1022:03第14页7.1.4线程的状态死亡状态(Dead)线程的终止一般可通过两种方法实现:自然撤消或是被停止。自然撤消是指从线程的run()方法正常结束退出,如果希望线程正常终止,一般可设置标记来使线程中的run()方法退出。调用线程的实例方法stop()则可以强制停止当前线程。既可以通过在其他线程中调用stop()方法来终止线程,也可以由线程自己调用stop()方法,自我终止。但这个方法已在JDK2中建议不再使用,应当避免使用。2020/1/1022:03第15页7.1.5线程的优先级处在就绪状态下的线程,可能有多个,它们各自任务的重要程度不同。Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定调度哪些线程来执行。多个线程运行时,具有高优先级的线程会在较低优先级的线程之前得到执行。同一优先级的线程,采取先进先出的原则由操作系统按时间片轮转方式或独占方式来分配线程的执行时间。同时线程的调度是抢先式的,即如果当前线程在执行过程中,一个具有更高优先级的线程进入可执行状态,则该高优先级的线程会被立即调度执行。2020/1/1022:03第16页7.1.5线程的优先级线程的优先级用数字来表示,范围从1到10,Thread类有三个关于优先级的静态常量:MIN_PRIORITY=1MAX_PRIORITY=10NORM_PRIORITY=5对应于一个新线程,系统会遵循以下原则:新线程将继承创建它的父线程的优先级。一般情况下,线程具有普通优先级。用户可以根据需要,通过setPriority()方法来修改优先级。2020/1/1022:03第17页7.2线程的使用方法Java中编程实现多线程有两种方式:由Thread类派生子类创建线程类;通过实现Runnable接口创建线程类。两种方法都要使用到Java.lang中的Thread类及其方法来实现。当生成一个Thread对象之后,就产生了一个线程,通过该对象,可以启动线程、终止线程、或者暂时休眠等。Thread类本身只是线程的虚拟CPU,线程所执行的代码(或者说线程所要完成的功能)是通过方法run()(包含在一个特定的对象中)来完成的,方法run()称为线程体。实现线程体的特定对象是在初始化线程时传递给线程的。在一个线程被建立并初始化以后,Java的运行时系统就自动调用run()方法,正是通过run()方法才使得建立线程的目的得以实现。2020/1/1022:03第18页7.2.1通过继承Thread类构造线程Tread类定义一个线程类,它继承类Thread,并重写其中的run()方法。这时在初始化这个类的实例时,目标对象target可以为null,表示这个实例本身具有线程体。由于Java只支持单继承,用这种方法定义的类不能再继承其他类。Tread类综合了Java程序中一个线程所需要拥有的属性和方法,主要有:构造方法线程优先级其他一些主要方法。2020/1/1022:03第19页7.2.1通过继承Thread类构造线程Thread类的构造方法如下:publicThread(ThreadGroupgroup,Runnabletarget,Stringname)group指明了线程所属的线程组;target是线程体run()方法所在的对象;name是线程的名称。target必须实现接口Runnable。在接口Runnable中只定义了一个方法voidrun()作为线程体。任何实现接口Runnable的对象都可以作为一个线程的目标对象。start()方法:启动线程,使线程由新建状态转为就绪状态;run()方法:定义该线程的操作;2020/1/1022:03第20页7.2.1通过继承Thread类构造线程sleep()方法:使线程进入到休眠状态。让其它线程得到机会执行。sleep()会抛出异常InterruptedException,必须捕获。isAlive()方法:可以用来判断线程目前是否正在执行状态中。如果线程已被启动并且未被终止,那么isAlive()返回true,但该线程是可运行或是不可运行的,是不能作进一步的分辨。如果返回false,则该线程是新创建或是已被终止的(同样不能作进一步的分辨)。join()方法:等待线程终止。yield()方法:将执行的权力交给其它优先级相同的线程,自己到可运行线程队列的最后等待,若队列空,该方法无效。2020/1/1022:03第21页7.2.1通过继承Thread类构造线程1.线程的创建与启动要创建并执行一个线程,须完成下列步骤:(1)创建一个类扩展Thread类。(2)用要在这个线程中执行的代码覆盖Thread类的run()方法。(3)用关键字new创建所定义的线程类的一个对象。(4)调用该对象的start()方法启动线程。【例7.1】创建一个Thread类的子类,显示1~8这8个数字,然后在另一个类中建立这个Thread类的3个对象来测试它,看执行时会发生什么现象。2020/1/1022:03第22页7.2.1通过继承Thread类构造线程使用线程的一些技巧如下步骤实现一种简单的机制,可在任何时候终止线程。·编写一个类扩展Thread类。·增加一个布尔变量running到这个类中,并初始化为false。·覆盖start()方法,置running为true,然后调用super.start()。·提供一个public方法halt(),它将running变量置为false。·在run()方法中使用类似于下例的while循环:publicvoidrun(){while(running){/*线程要执行的代码*/}}如果halt()方法被调用,就会引起run()方法终止执行,结束该线程。2020/1/1022:03第23页7.2.1通过继承
本文标题:java多线程与异常处理.
链接地址:https://www.777doc.com/doc-2880891 .html