面向对象程序设计-Java(第四版)课件 第14章 多线程_第1页
面向对象程序设计-Java(第四版)课件 第14章 多线程_第2页
面向对象程序设计-Java(第四版)课件 第14章 多线程_第3页
面向对象程序设计-Java(第四版)课件 第14章 多线程_第4页
面向对象程序设计-Java(第四版)课件 第14章 多线程_第5页
已阅读5页,还剩42页未读 继续免费阅读

下载本文档

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

文档简介

第14章多线程14.1Java中的多线程实现技术14.2多线程的管理

14.1Java中的多线程实现技术

每个Java程序都有一个缺省的主线程main( )方法。要想实现多线程,必须在主线程中创建新的线程对象。可以通过继承Thread类或实现Runnable接口的途径来创建线程。线程的生命周期多线程机制是Java语言的又一重要特征,使用多线程技术可以使系统同时运行多个执行体,这样就可以加快程序的响应时间,提高计算机资源的使用效率。新建的线程在它的一个完整的生命周期中通常要经历新生、就绪、运行、阻塞和死亡等五种状态,这五种状态之间的转换关系和转换条件如图所示。线程的生命周期1.新生状态

当用new关键字和某线程类的构造方法创建一个线程对象后,这个线程对象处于新生状态,此时它已经有了相应的内存空间,并已被初始化。处于该状态的线程可通过调用start( )方法进入就绪状态。

2.就绪状态

处于就绪状态的线程已经具备了运行的条件,但尚未分配到CPU资源,因而它将进入线程队列排队,等待系统为它分配CPU。一旦获得了CPU资源,该线程就进入运行状态,并自动地调用自己的run方法。此时,它脱离创建它的主线程,独立开始了自己的生命周期。3.运行状态

进入运行状态的线程执行自己的run方法中的代码。若遇到下列情况之一,将终止run方法的执行:

(1)终止操作。调用当前线程的stop方法或destroy方法进入死亡状态。

(2)等待操作。调用当前线程的join(millis)方法或wait(millis)方法进入阻塞状态。当线程进入阻塞状态时,在millis(毫秒)内可由其他线程调用notify或notifyAll方法将其唤醒,进入就绪状态。在millis内若不唤醒,则需等待到当前线程结束。

(3)睡眠操作。调用sleep(millis)方法来实现。当前线程停止执行后,会处于阻塞状态,睡眠millis(毫秒)之后重新进入就绪状态。

(4)挂起操作。通过调用suspend方法来实现。将当前线程挂起,进入阻塞状态,之后当其他线程调用当前线程的resume方法后,才能使其进入就绪状态。

(5)退让操作。通过调用yield方法来实现。当前线程放弃执行,进入就绪状态。

(6)当前线程要求I/O时,则进入阻塞状态。

(7)若分配给当前线程的时间片用完,则当前线程进入就绪状态。若当前线程的run方法执行完,则线程进入死亡状态。4.阻塞状态

一个正在执行的线程在某些特殊情况下,如执行了suspend、join或sleep方法,或等待I/O设备的使用权,那么它将让出CPU并暂时中止自己的执行,进入阻塞状态。阻塞时它不能进入就绪队列,只有当引起阻塞的原因被消除时,线程才可以转入就绪状态,重新进到线程队列中排队等待CPU资源,以便从原终止处开始继续运行。

5.死亡状态

处于死亡状态的线程将永远不再执行。线程死亡有两个原因:一是正常运行的线程完成了它的全部工作;二是线程被提前强制性地终止了。例如,通过执行stop或destroy方法来终止线程。Thread类

Thread类(线程类)是java.lang包中的一个专门用来创建线程和对线程进行操作的类。Java在Thread类中定义了许多方法,这些方法可以帮助我们运用和处理线程。这些方法可分为四组:(1)构造方法。该方法用于创建用户的线程对象。

java.lang.Thread类的构造方法

(2) run( )方法。该方法用于定义用户线程所要执行的操作。(3)改变线程状态的方法,如start( )、sleep( )、stop( )、suspend( )、resume( )、yield( )和wait( )方法等。这是最常用的一组方法。(4)其他方法,如setPriority( )、setName( )等。表14.2列出了Thread类的后三组方法。java.lang.Thread类的常用方法

通过继承Thread类创建并执行线程的程序步骤如下:

定义一个继承Thread类的子类,其中:

(1)重写Thread类中的run()方法,将自己要执行的任务写在run()方法中;

(2)main()方法中的主要内容:

①创建Thread类的子类线程;

②调用Thread类中的方法start()方法启动新线程,并执行run()方法;

如果创建Thread类的子类线程创建后不再用,可以使用thread的匿名子类。通过继承Thread类创建线程

【示例程序C14_1.java】创建Thread类的子类thd1与thd2线程,获取线程编号及线程名。通过实现Runnable接口创建线程Runnable接口中只有一个run()方法,因此,实现Runnable接口需要实现run()方法。通过实现Runnable接口创建并执行线程的程序步骤如下:

1.定义Runnable接口的实现类,重写Runnable接口的run()方法,将自己要执行的任务写在run()方法中;

2.定义一个主类,main()方法中的主要内容

(1)创建Runnable接口的实现类对象;

(2)将Runnable接口的实现类对象作为实参创建Thread类线程对象;

(3)调用start()方法启动创建的线程对象并自动执行重写的run()方法。

【示例程序C14_2.java】通过实现Runnable接口创建线程,获取线程的名字。用多线程实现简单动画

在paint()方法中画一个圆,每次使用repaint()方法重新调用paint()方法绘制这个圆时,如果能够改变这个圆的位置,则就实现了简单动画。在JPanel画板上实现简单动画的步骤如下:定义一个继承JPanel类及实现Runnable接口的子类,其中;(1)设置圆左上角坐标位置(x,y);(2)重写pain()方法绘制简单图形,即绘制圆;(3)重写run()方法,改变简单图形的坐标位置、使用repaint()方法重新调用paint()方法绘制图形,并通过sleep()方法控制运动速度;(4)在main()方法中的内容

①创建一个继承JPanel类及实现Runnable接口的子类对象;

②将①创建的对象作为实参创建Thread类的线程;

③将①对象作为画板添加到JFrame画框对象中;

④调用start()方法启动创建的线程对象并自动执行重写的run()方法。

【示例程序C14_3.java】如图14.2所示。通过创建线程,实现圆在屏幕上横向运动。

如果在paint()方法中绘制一个字符串,每次使用repaint()方法重新调用paint()方法时,都能改变这个字符串的绘制位置,则在JPanel画板上可以用以下步骤实现:定义一个JPanel类的子类,在子类中:(1)定义一个该子类的构造方法,构造方法的形参是Thread类的子类对象。在方法体中创建Thread类的子类对象,调用strat()方法,自动执行run()方法;(2)重写paint()方法,获取设置的字体,绘制字符串;(3)在main()方法中的主要内容①创建一个Thread类的子类对象,创建JPanel类的子类对象,自动调用Thread类的子类对象作为实参的JPanel类的子类构造方法;

②调用JPanel类的子类对象作为实数的Thread类的子类对象的csp()方法;2.定义一个Thread类的子类,在子类中:(1)创建字符串Message对象,创建f字体对象,设置字符串的起始坐标位置(x,y);(2)定义一个csp()方法,JPanel类的子类对象作为该方法的参数,在方法体中创建JPanel类的子类对象;(3)重写run()方法,改变字符串的绘制位置、使用repaint()方法重新调用paint()方法绘制图形,并通过sleep()方法控制运动速度;

【示例程序C14_4.java】通过创建线程,实现“JavaNow!”在屏幕上不停走动。【示例程序C14_5.java】通过创建两个线程实现“JavaNow!”与矩形框在屏幕上呈相反方向的不停走动。该程序由三个程序组成:①实现屏幕上的字符“JavaNow!”走动的线程程序CString.java;②实现屏幕上矩形框走动的线程程序CSquare.java,③主程序C14_5.java。

(1)主程序C14_5.java(2) CString.java程序(3) CSquare.java程序:14.2多线程管理线程调度

在单CPU的计算机上运行多线程程序,或者当线程数多于处理机的数目时,势必存在多个线程争用CPU的情况,这时需要提供一种机制来合理地分配CPU,使多个线程有条不紊、互不干扰地工作,这种机制称为调度。

在Java运行系统中,由线程调度器对线程按优先级进行调度。线程调度器中写好了相应的调度算法,当有多个线程在同一时刻处于就绪状态时,线程调度器会选择优先级最高的线程运行。

如果发生下列情况之一,调度器就会终止此线程的运行:(1)本线程的线程体中调用了yield( )方法,从而让出了对CPU的占有权;(2)本线程的线程体中调用了sleep( )方法,使线程进入睡眠状态;(3)本线程由于I/O操作而进入阻塞状态;(4)另一个具有更高优先级的线程从睡眠状态被唤醒,或其I/O操作完成而返回就绪状态。Java的线程调度算法:(1)优先抢占式调度。当线程的优先级不同时,为保证优先级最高的线程先运行而采用优先抢占式调度算法,即优先级高的线程优先抢占CPU。例如,在程序的运行过程中若设置线程A具有最高优先级,则线程A将立即取代正在运行的其他线程,直到线程A处于阻塞状态或运行结束。(2)队列轮转调度。当若干个线程的优先级相同时,可采用队列轮转调度算法,即当一个线程运行结束时,该优先队列中排在最前面的线程运行。如果某个线程由于睡眠或I/O阻塞成为一个等待再次运行的线程,那么当它恢复到可运行状态后,即被插入到该队列的队尾,必须等到其他具有相同优先级的线程都被调度过一次后,才有机会再次运行。线程优先级

运行的每个线程都有优先级。优先级是1~10之间的正整数。数值越大,优先级越高,未设定优先级的线程其优先级取缺省值5。Java线程的优先级设置遵从下述原则:(1)线程创建时,子线程继承父线程的优先级。(2)线程创建后,可在程序中通过调用setPriority( )方法改变线程的优先级。(3)用标识符常量MIN_PRIORITY表示优先级为1,MAX_PRIORITY表示优先级为10,默认情况下,用NORM_PRIORITY表示优先级为5。线程优先级为8。例如:setPriority(Thread.NORM_PRIORITY+3);

【示例程序C14_6.java】创建三个线程A、B、C,根据优先级确定线程的执行顺序。线程同步

当两个或两个以上的线程需要共享同一资源时,线程之间的执行次序就需要协调。

例如:生产者与消费者问题。它是一个多线程同步问题的经典案例,描述有一块缓冲区作为仓库,生产者生产产品放入缓冲区,消费者从缓冲区中取走产品消费。

约束条件:生产者与消费者互斥访问缓冲区,即一次只能放一个或取一个产品,当缓冲区满时生产者暂停生产,等待消费者消费产品,当缓冲区空时消费者暂停消费,等待生产者生产产品。缓冲区生产者消费者JDK5.0之后提供的更加健壮的多线程同步处理机制,使用await()/signal()方法解决生产者消费者的同步问题。假设:一个生产者,一个消费者,一个缓冲区,缓冲区最多只能放4个产品,生产者一次只能送一个生产的产品到仓库,最多只能生产8个产

温馨提示

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

评论

0/150

提交评论