您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > Java 程序设计第11章 线程
第11章线程线程的概念程序是一段静态的代码,它是应用程序执行的蓝本一个进程既包括其所要执行的指令,也包括了执行指令所需的任何系统资源,如CPU、内存空间、I/O端口等,不同进程所占用的系统资源相对独立线程是进程执行过程中产生的多条执行线索,是比进程单位更小的执行单位线程的结构CPUCodeData虚拟CPU,封装在java.lang.Thread类中,它控制着整个线程的运行执行的代码,传递给Thread类,由Thread类控制顺序执行处理的数据,传递给Thread类,是在代码执行过程中所要处理的数据线程与进程线程在形式上同进程十分相似—都是用一个顺序执行的语句序列来完成特定的功能不同之处:线程没有入口,也没有出口,因此其自身不能自动运行,而必须栖身于某一进程之中,由进程触发执行在系统资源的使用上,属于同一进程的所有线程共享该进程的系统资源,但是线程之间切换的速度比进程切换要快得多进程与线程的区别文件输入输出装置各种系统资源数据区段程序区段只有一个地方在执行文件输入输出装置各种系统资源数据区段程序区段同时有数个地方在执行传统的进程多线程的任务多线程的优势多线程编程简单,效率高。使用多线程可以在线程间直接共享数据和资源,而多进程之间不能做到这一点适合于开发服务程序如Web服务、聊天服务等适合于开发有多种交互接口的程序如聊天程序的客户端、网络下载工具适合于有人机交互又有计算量的程序如字处理程序Word、Excel等线程的状态Java的线程是通过Java的软件包java.lang中定义的类Thread来实现的当生成一个Thread类的对象之后,就产生了一个线程。通过该对象实例,可以启动线程、终止线程,或者暂时挂起线程等Thread类本身只是线程的虚拟CPU,线程所执行的代码是通过方法run()来完成的,方法run()称为线程体在一个线程被建立并初始化以后,Java的运行时系统就自动调用run()方法,正是通过run()方法才使得建立线程的目的得以实现线程的状态线程一共有四种状态:新建(new)、可运行状态(runnable)、死亡(dead)及堵塞(blocked)newThread()创建新线程可运行态start()不可运行态stop()stop()死亡yield()stop()run()exitsuspend()sleep()wait()I/O流阻塞resume()notify()/notifyAll()I/O指令等待睡眠挂起阻塞就绪运行新建线程对象刚刚创建,还没有启动,此时还处于不可运行状态Threadthread=newThread(“test”)此时线程thread处于新建状态,但已有了相应的内存空间以及其它资源可运行状态runnable此时的线程已经启动,处于线程的run()方法之中。这种情况下线程可能正在运行,也可能没有运行,只要CPU一空闲,马上就会运行调用线程的start()方法可使线程处于“可运行”状态thread.start();死亡(dead)线程死亡的原因:run()方法中最后一个语句执行完毕当线程处于“可运行”状态时,调用了stop()方法结束了线程的运行,使其进入了死亡状态thread.stop();阻塞(blocked)一个正在执行的线程因特殊原因,被暂停执行,就进入阻塞状态阻塞时线程不能进入队列排队,必须等到引起阻塞的原因消除,才可重新进入排队队列引起阻塞的原因很多,不同原因要用不同的方法解除sleep()和wait()是两个常用的引起阻塞的方法中断线程interrupt()向一个线程发送一个中断请求,同时把这个线程的“interrupted”状态置为true。若该线程处于“blocked”状态,会抛出InterruptedException异常staticbooleaninterrupted()检测当前线程是否已被中断,并重置状态“interrupted”值为falsebooleanisInterrupted()检测当前线程是否已被中断,不改变状态“interrupted”值创建线程类Thread的构造方法如下publicThread(ThreadGroupgroup,Runnabletarget,Stringname)指明了线程所属的线程组是线程体run()方法所在的对象,必须实现接口Runnable线程的名称创建线程的方法创建线程的方法一——继承Thread类定义一个线程类,它继承类Thread并重写其中的方法run()。在初始化这个类的实例时,目标对象target可以为null,表示这个实例本身具有线程体创建线程的方法二——实现Runnable接口Runnable是Java中用以实现线程的接口,从根本上讲,任何实现线程功能的类都必须实现该接口方法一从Thread类派生出一个子类,在类中一定要实现run()然后用该类创建一个对象用start()方法启动线程(程序11-111-2)classLefthandextendsThread{publicvoidrun(){……}}Lefthandleft=newLefthand();left.start();方法二Thread的构造方法中包含有一个Runnable实例的参数,必须定义一个实现Runnable接口的类并产生一个该类的实例,对该实例的引用就是适合于这个构造方法的参数classBallThreadextendsAppletimplementsRunnable{publicvoidstart(){thread=newThread(this);thread.start();}privateThreadthread;}publicclassxyzimplementsRunnable{inti;publicvoidrun(){while(true){System.out.println(Hello+i++);}}}Runnabler=newxyz();Threadt=newThread(r);CPUCodeDataThreadtxyzrclassxyz线程模拟小球例子程序11-3是一个模拟小球平抛和自由落体的例子BallThread.java相应的HTML文档两种方法的讨论适用于采用实现Runnable接口方法的情况需要多继承的情况,比如对于Applet程序保持程序风格的一贯性适用于采用继承Thread方法的情况为代码稍微简洁一些在以后的继承中可能会出现麻烦线程的启动通过Thread类中方法start()来启动在程序11-3中,只要执行:red.start();blue.start();线程的操作方法start()启动线程对象;run()用来定义线程对象被调度之后所执行的操作,用户必须重写run()方法;yield()强制终止线程的执行;isAlive()测试当前线程是否在活动;sleep(intmillsecond)使线程休眠一段时间,时间长短由参数所决定;voidWait()使线程处于等待状态;线程的调度线程调度通常是抢占式,而不是时间片式抢占式调度是指可能有多个线程准备运行,但只有一个在真正运行。一个线程获得执行权,这个线程将持续运行下去,直到它运行结束或因为某种原因而阻塞,再或者有另一个高优先级线程就绪,最后一种情况中称为低优先级线程被高优先级线程所抢占。优先级策略优先级高的先执行,优先级低的后执行多线程系统会自动为每个线程分配一个优先级,缺省时,继承其父类的优先级任务紧急的线程,其优先级较高同优先级的线程按“先进先出”的原则线程优先级Thread类三个与线程优先级有关的静态量Thread类中几个常用的有关优先级的方法MAX_PRIORITY:最大优先权,值为10;MIN_PRIORITY:最小优先权,值为1;NORM_PRIORITY:默认优先权,值为5VoidsetPriority(intnewPriority)//重置线程优先级IntgetPriority()//获得当前线程的优先级Staticvoidyield()//使当前线程放弃执行权线程的调度被阻塞的线程按次序排列,组成一个阻塞队列。所有就绪但没有运行的线程则根据其优先级排入一个就绪队列CPU空闲时,如果就绪队列不空,队列中第一个具有最高优先级的线程将运行当一个线程被抢占而停止运行时,它的运行态被改变并放到就绪队列的队尾;同样,一个被阻塞(可能因为睡眠或等待I/O设备)的线程就绪后通常也放到就绪队列的队尾为保证给其他线程留有执行的机会,可以通过间隔地调用sleep()线程的调度例例11-4publicclassxyzimplementsRunnable{publicvoidrun(){while(true){……//执行若干操作//给其他线程运行的机会try{Thread.sleep(10);}catch(InterruptedExceptione){//该线程为其他线程所中断}}}}sleep()是静态方法,可以通过Thread.sleep(x)直接引用x指定了线程在再次启动前必须休眠的最小时间,毫秒为单位可能引发中断异常InterruptedException,因此要进行捕获和处理“最小时间”是因为这个方法只保证在一段时间后线程回到就绪态,至于它是否能够获得CPU运行,则要视线程调度而定,所以,通常线程实际被暂停的时间都比指定的时间要长yield()可以给其他同等优先级线程一个运行的机会如果在就绪队列中有其他同优先级的线程,yield()把调用者放入就绪队列尾,并允许其他线程运行;如果没有这样的线程,则yield()不做任何工作sleep()调用允许低优先级进程运行,而yield()方法只给同优先级进程以运行机会线程的基本控制结束线程当一个线程从run()方法的结尾处返回时,它自动消亡并不能再被运行,可以将其理解为自然死亡利用stop()方法强制停止,可以将其理解为强迫死亡,这种方法必须用于Thread类的特定实例中结束线程例例11-5强迫死亡利用Thread类中的静态方法currentThread()来引用正在运行的线程,见例11-6在这个例子中,执行stop()将破坏当前的运行环境,因而run()中的循环在此情况下将不再运行检查线程isAlive()获取一个线程是否还在活动状态的信息。活动状态不意味着这个线程正在执行,而只说明这个线程已被启动,并且既没有运行stop(),也尚未运行完方法run()。挂起线程暂停一个线程称为挂起。在挂起之后,必须重新唤醒线程进入运行挂起线程的方法sleep()线程不是休眠期满后就立刻被唤醒,因为此时其他线程能正在执行,重新调度只在以下几种情况下才会发生:1)被唤醒的线程具有更高的优先级;2)正在执行的线程因为其他原因被阻塞;3)程序处于支持时间片的系统中suspend()和resume()join():引起现行线程等待,直至方法join所调用的线程结束程序11-4suspend()和resume()程序11-4说明:线程t在运行到suspend()以后被强制挂起,暂停运行,直到主线程调用t.resume()时才被重新唤醒;一个线程只能被不同于它自身的线程所唤醒,因为在执行suspend()方法以后,这个线程其后的代码都不会被执行到,而该线程又依赖于其后的resume语句将其唤醒,所以千万不能将resume()用在已被挂起的线程语句中join()例11-7已经生成并运行了一个线程tt,而在另一线程中执行方法timeout(),其定义如下,在执行方法timeout()以后,现行的线程将被阻塞,直到tt运行结束publicvoidtimeout(){//暂停该线程,等候其他线程结束tt.join();//其他线程结束后,继续执行该线程…………}join()方法在调用时也可以使用一个以毫秒计的时间值,此时join方法将挂起现行线
本文标题:Java 程序设计第11章 线程
链接地址:https://www.777doc.com/doc-4471871 .html