java语言程序设计第7章_第1页
java语言程序设计第7章_第2页
java语言程序设计第7章_第3页
java语言程序设计第7章_第4页
java语言程序设计第7章_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

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

文档简介

1、第7章 线程及其操作传统的程序设计语言,其程序在同一时刻只能单任务操作,效率非常低。例如程序往往在接收数据输入时发生阻塞,只有等到程序获得数据后才能继续运行。因此,很多时候,在程序设计中,我们需要编写具有多线程的程序,以便提高程序执行效率和处理能力。本章要点7.1 线程的实现7.2 线程的状态及调度7.3 线程的同步思考与练习77.1 线程的实现7.1.1 线程的定义程序是一段静态的代码,它是应用软件执行的蓝本。平常所说的多任务就是在操作系统中同时运行几个相同或不相同的应用程序,每个程序占用一个进程。进程是程序的一次动态执行过程,它对应了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进

2、程本身从产生、发展到消亡的过程。作为执行蓝本的同一段程序,可以被多次加载到系统的不同内存区域分别执行,形成不同的进程。线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同的是,同类的多个线程是共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈。所以系统在产生一个线程,或者在各个线程之间切换时,负担要比进程小的多。一个进程中可以包含多个线程。7.1 线程的实现7.1.1 线程的定义一个线程是一个程序内部的顺序控制流。多进程是指在操作系统中,能同时运行多个任务程序。多线程是指在同一应用程序中,有多个顺序流同时

3、执行。多任务与多线程是两个不同的概念。前者是针对操作系统而言的,表示操作系统可以同时运行多个应用程序;后者是针对一个程序而言的,表示一个程序内部可以同时执行多个线程。多线程的程序能更好地表述和解决现实世界的具体问题,是计算机应用开发和程序设计的一个必然发展趋势。 7.1 线程的实现7.1.2 创建线程创建线程是指将需要独立运行的子任务代码放到从Thread类派生出来的类的run方法中。然后在主线程中原先调用该子任务的地方先创建一个该线程类的实例,再调用线程类中的start方法启动线程。每个Java程序都有一个缺省的主线程,对于Application,主线程是main( )方法执行的线索;对于A

4、pplet,主线程指挥浏览器加载并执行Java小程序。要想实现多线程,必须在主线程中创建新的线程对象。Java中实现多线程有两种途径:1创建Thread类的子类2实现Runnable接口无论使用哪种方法,都需要用到Java基础类库中的Thread类及其方法。7.1 线程的实现7.1.2 创建线程7.1.2.1 继承Thread类Thread类综合了Java程序中一个线程需要拥有的属性和方法,主要有:1构造方法public Thread(ThreadGroup group,Runnable target,String name)其中,参数group代表该线程所属的线程组,target代表执行线程

5、体的目标对象(该对象必须实现Runnable接口),name代表线程名。Thread类的构造方法有多个,所对应的操作有如下几种:(1)public Thread():创建一个系统线程类的对象。(2)public Thread(Runnable target):在上一个构造方法完成的操作创建线程对象的基础之上,利用参数对象(实现了Runnable接口的target对象)中所定义的run()方法,来初始化或覆盖新创建的线程对象的run( )方法。7.1 线程的实现7.1.2 创建线程7.1.2.1 继承Thread类(3)public Thread(String name):在第一个构造方法的基础

6、上,为所创建的线程对象指定一个字符串名称供以后使用。(4)public Thread(Runnable target,String name):实现前两个构造方法的功能。(5)public Thread(ThreadGroup group,Runnable target):生成一个指定线程组和目标对象的线程。(7)public Thread(ThreadGroup group,String name):生成一个指定线程组和名字的线程。利用构造方法创建新线程对象之后,这个对象中的有关数据被初始化,从而进入线程的生命周期的第一个状态新建状态。7.1 线程的实现7.1.2 创建线程7.1.2.1 继

7、承Thread类2Thread类的主要方法包括:(1)void run():线程所执行的代码。(2)void start():启动线程对象,使之从新建状态转入就绪状态,多次调用会产生异常。(3)void sleep(long milis):让线程睡眠一段时间,此期间线程不消耗CPU资源,以毫秒为时间单位。(4)void interrupt():中断线程。(5)static boolean interrupted():判断当前线程是否被中断(会清除中断状态标记)。7.1 线程的实现7.1.2 创建线程7.1.2.1 继承Thread类2Thread类的主要方法包括:(7)boolean isAl

8、ive():判断线程是否处于活动状态(即已调用start,但run还未返回)。(8)Thread currentThread():返回当前线程对象的引用。(9)void setName(String threadName):改变线程的名字。(10)String getName():取得由setName()方法设置的线程名字的字符串。(11)void join():等待线程结束7.1 线程的实现7.1.2 创建线程7.1.2.1 继承Thread类2Thread类的主要方法包括:(12)suspend():使线程挂起,暂停运行。(13)resume():恢复挂起的线程,使处于可运行状态。(14)

9、yield():将CPU控制权主动移交到下一个可运行线程。(15)setPriority(int p):设置线程优先级。(16)getPriority():返回线程优先级。用Java提供的线程类Thread来创建线程与创建普通类的对象操作是一样的,而线程就是Thread类或其子类的实例对象。7.1 线程的实现7.1.2 创建线程7.1.2.1 继承Thread类2Thread类的主要方法包括:下面是一个创建启动一个线程的语句:Thread mythread = new Thread();/声明一个对象实例,即创建一个线程mythread.start();/用Thread类中的start()方法

10、启动线程从上面语句,我们可以通过Thread()构造方法创建一个线程,并启动该线程。事实上,启动线程也就是启动线程的run()方法,而Thread类中的run()方法没有任何操作语句,所以这个线程没有任何操作。要使线程实现预定功能,必须定义自己的run()方法。 7.1 线程的实现7.1.2 创建线程7.1.2.2 实现Runnable接口Runnable接口只有一个方法run( ),所有实现Runnable接口的用户类都必须具体实现这个run( )方法,为它书写方法体并定义具体操作。使用实现Runnable接口的方法创建线程时,使用Runnable目标对象初始化Thread类,由目标对象来提

11、供run()方法,即通过向Thread类的构造方法传递Runnnable对象来创建线程。可以用下列步骤创建线程:1定义一个实现Runnable接口的类并生成实例。2生成一个Thread类实例。3将生成的Runnable实例作为参数传递给Thread构造方法。7.1 线程的实现7.1.2 创建线程7.1.2.2 实现Runnable接口例如:public class ThreadTest implements RunnableThreadTest myTest=new ThreadTest();Thread myThread=new Thread(myTest);myThread.start()

12、;直接继承Thread的特点是:编写简单,可以直接操纵线程;但缺点也是明显的,因为若继承Thread类,就不能再继承其他类,因为Java是单重继承的语言。7.1 线程的实现7.1.2 创建线程7.1.2.2 实现Runnable接口使用Runnable接口,这种方法的特点是:可以将Thread类与所要处理的任务的类分开,形成清晰的模型;还可以从其他类继承。如果想让线程作为Applet应用程序的一部分而运行,经常使用Runnable接口这种方法。因为Java语言不支持多继承,即子类只能有一个父类,而Applet应用程序必须继承java.applet.Applet类,此时可用实现Runnable接

13、口来定义线程。如果是Applet程序,也可用下列方法来实现线程: 1定义一个线程类,实现线程体。2在小应用程序中生成该类的实例并启动运行。7.2 线程的状态及调度7.2.1 线程的状态Java语言使用Thread类及其子类的对象来表示线程,新建的线程在它的一个完整的生命周期中通常要经历如下的五种状态:1新建当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态。此时它已经有了相应的内存空间和其他资源,并已被初始化。例如,下面的语句就可以创建一个新的线程:Thread myThread = new MyThreadClass();其中MyThreadClass是Thread

14、的子类。2就绪处于新建状态的线程被启动后,将进入线程队列排队等待CPU时间片,此时它已经具备了运行的条件。一旦轮到它来享用CPU资源时,就可以脱离创建它的主线程独立开始自己的生命周期了。另外原来处于阻塞状态的线程被解除阻塞后也将进入就绪状态。7.2 线程的状态及调度7.2.1 线程的状态3运行当就绪状态的线程被调度并获得处理器资源时,便进入运行状态。每一个Thread类及其子类的对象都有一个重要的run( )方法,当线程对象被调度执行时,它将自动调用本对象的run( )方法,从第一句开始顺次执行。run( )方法定义了这一类线程的操作和功能。4阻塞一个正在执行的线程在某些特殊情况下,如被人为挂

15、起或需要执行费时的输入输出操作时,将让出CPU并暂时中止自己的执行,进入阻塞状态。阻塞时它不能进入排队队列。只有当引起阻塞的原因被消除时,线程才可以转入就绪状态,重新进到线程队列中排队等待CPU资源,以便从原来终止处开始继续运行。当下面情况发生时,线程就进入阻塞状态:(1)调用了sleep()方法;(2)调用了suspend()方法;(3)为等候一个条件变量,线程调用wait()方法;(4)输入/输出(I/O)流中发生线程阻塞。7.2 线程的状态及调度7.2.1 线程的状态例如,下面的例子调用了sleep()方法,使线程由运行状态进入阻塞状态:Thread myThread = new MyT

16、hreadClass();myThread.start();try myThread.sleep(10000); catch (InterruptedException e) 在这个例子中我们可以看到通过调用sleep()方法使得myThread线程休止了10秒(10000毫秒),这时即使处理器空闲,也不能执行该线程。10秒结束以后,myThread又成为可运行的了。7.2 线程的状态及调度7.2.1 线程的状态5死亡处于死亡状态的线程不具有继续运行的能力。有两种情况可以使线程死亡:(1)自然死亡:正常运行的线程完成了它的全部工作,即执行完了run( )方法的最后一个语句并退出。下面的例子中w

17、hile语句循环10次后将退出:public void run()int i = 0;while (i 10)i+;System.out.println(i = + i);也就是说当run()方法结束后,该线程就自然死亡。7.2 线程的状态及调度7.2.1 线程的状态5死亡(2)强制死亡:线程被提前强制性终止,如通过执行stop( )方法或destroy( )终止线程。下面的例子强行终止了线程:Thread myThread = new MyThreadClass();myThread.start();tryThread.currentThread().sleep(10000); catch

18、(InterruptedException e)myThread.stop();在这个例子中,创建并开始了myThread线程,然后休息了10秒,当它被唤醒时,又调用stop()方法终止了该线程。 7.2 线程的状态及调度7.2.2 线程的调度与优先级当一个在就绪队列中排队的线程被分配给CPU资源而进入运行状态后,这个线程就称为被“调度”或被线程管理器选中了。Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定应调度哪些线程来执行。线程调度器按线程的优先级高低选择高优先级线程(进入运行中状态)执行,同时线程调度是抢先式调度,即如果在当前线程执行过程

19、中,一个更高优先级的线程进入可运行状态,则这个线程立即被调度执行。Java中线程的优先级从低到高以整数110表示,共分为10级,设置优先级是通过调用线程对象的setPriority()方法。7.2 线程的状态及调度7.2.2 线程的调度与优先级例如,设置优先级的语句为:thread1 threadone=new thread1(); /用Thread类的子类创建线程;Thread threadtwo=new Thread(new thread2();/用Thread类的对象创建线程;threadone.setPriority(7);/设置threadone的优先级7;threadtwo.set

20、Priority(3);/设置threadtwo的优先级3;threadone.start();threadtwo.start();/strat()方法启动线程;这样,线程threadone将会优先于线程threadtwo执行,并将占有更多的CPU时间。该例中,优先级设置放在线程启动前,也可以在启动后进行设置,以满足不同的优先级需求。7.2 线程的状态及调度7.2.2 线程的调度与优先级Thread类还定义了3个常数,来表示线程优先级:1MAX_PRIORITY:最高优先级(值为10)2MIN_PRIORITY:最低优先级(值为1)3NORM_PRIORITY:默认优先级(值为5)线程创建时,

21、继承了父线程的优先级。父线程是指执行创建新线程对象语句的线程,它可能是主线程,也可能是用户自己定义的线程。一般情况下,主线程具有默认优先级。在线程创建之后,可以通过getPriority()方法得到线程的优先级,也可以通过setPriority()方法改变线程的优先级。7.2 线程的状态及调度7.2.3 控制线程线程的控制包括结束线程、测试线程、延迟线程和设定线程的优先级等。7.2.3.1 结束线程当一个线程正常结束运行并终止时,它就不能再运行了。我们也可以通过执行stop()方法或destroy()终止线程。7.2.3.2 测试线程可以通过Thread 中的isAlive() 方法来获取线程

22、是否处于活动状态;线程由start() 方法启动后,直到其被终止之间的任何时刻,都处于运行状态7.2.3.3 线程的暂停和恢复有几种方法可以暂停一个线程的执行,在适当的时候再恢复其执行。(1)sleep() 方法当前线程睡眠(停止执行)若干毫秒,线程由运行状态进入不可运行状态,停止执行时间到后线程进入可运行状态。7.2 线程的状态及调度7.2.3 控制线程(2)suspend()和resume()方法线程的暂停和恢复,通过调用线程的suspend()方法使线程暂时由可运行状态切换到不可运行状态,若此线程想再回到可运行状态,必须由其他线程调用resume()方法来实现。(3)join()当前线程

23、等待调用该方法的线程结束后, 再恢复执行。TimerThread tt=new TimerThread(100);tt.start();public void timeout()tt.join();/ 当前线程等待线程tt 执行完后再继续往下执行 7.3 线程的同步在使用多线程时,由于可以共享资源,有时就会发生冲突。例如,有两个线程thread1负责写,thread2负责读,当它们操作同一个对象时,会发现由于thread1与thread2是同时执行的,因此可能thread1修改了数据而thread2读出的仍为旧数据,此时用户将无法获得预期的结果。问题之所以产生主要是由于资源使用协调不当(不同步

24、)造成的。以前,这个问题一般由操作系统解决,而Java提供了自己协调资源的方法。Java提供了同步方法和同步状态来协调资源。Java规定:被宣布为同步(使用Synchronized关键字)的方法、对象或类数据,在任何一个时刻只能被一个线程使用。通过这种方式使资源合理使用,达到线程同步的目的。1用Java关键字synchonized同步对共享数据操作的方法:在一个对象中,用synchonized声明的方法为同步方法。Java中有一个同步模型-监视器,负责管理线程对对象中的同步方法的访问,它的原理是:赋予该对象唯一一把“钥匙”,当多个线程进入对象,只有取得该对象钥匙的线程才可以访问同步方法,其它线

25、程在该对象中等待,直到该线程用wait()方法放弃这把钥匙,其它等待的线程抢占该钥匙,抢占到钥匙的线程才可得以执行,而没有取得钥匙的线程仍被阻塞在该对象中等待。7.3 线程的同步2利用wait()、notify()及notifyAll()方法发送消息实现线程间的相互联系:Java程序中多个线程是通过消息来实现互动联系的,这几种方法实现了线程间的消息发送。例如定义一个对象的synchonized 方法,同一时刻只能够有一个线程访问该对象中的同步方法,其它线程被阻塞。通常可以用notify()或notifyAll()方法唤醒其它一个或所有线程。而使用wait()方法来使该线程处于阻塞状态,等待其它的线程用notify()唤醒。下面,我们通过一个程序片断来理解线程的同步。public void run()int i=0;while(keepRunning) i+;/i代表循环次数/输出结果SynchronizedShow.show(getName(),i);SynchronizedShow.println(getName()+is dead!);class SychronizedShow/方法show(String,int)被宣布为同步的方法,因此每次只有一个线程能调用这个方法public static synchronized void sho

温馨提示

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

评论

0/150

提交评论