Java程序设计教程 教学课件 ppt 作者 978-7-302-18214-6第8章-多线程

上传人:w****i 文档编号:94406277 上传时间:2019-08-06 格式:PPT 页数:47 大小:528KB
返回 下载 相关 举报
Java程序设计教程 教学课件 ppt 作者  978-7-302-18214-6第8章-多线程_第1页
第1页 / 共47页
Java程序设计教程 教学课件 ppt 作者  978-7-302-18214-6第8章-多线程_第2页
第2页 / 共47页
Java程序设计教程 教学课件 ppt 作者  978-7-302-18214-6第8章-多线程_第3页
第3页 / 共47页
Java程序设计教程 教学课件 ppt 作者  978-7-302-18214-6第8章-多线程_第4页
第4页 / 共47页
Java程序设计教程 教学课件 ppt 作者  978-7-302-18214-6第8章-多线程_第5页
第5页 / 共47页
点击查看更多>>
资源描述

《Java程序设计教程 教学课件 ppt 作者 978-7-302-18214-6第8章-多线程》由会员分享,可在线阅读,更多相关《Java程序设计教程 教学课件 ppt 作者 978-7-302-18214-6第8章-多线程(47页珍藏版)》请在金锄头文库上搜索。

1、第8章 多线程,本章学习目标,理解多线程的定义。 掌握线程的两种创建方法。 掌握线程的生命期及状态。 理解线程的同步。 掌握线程的调度方法和优先级设置。 掌握线程控制的一些方法。 了解线程组的概念及其实现方法。,多线程,概述 多线程的创建 线程的生命期及其状态 线程的同步,线程的优先级和调度 守护线程 线程组,概述,进程和线程 单线程和多线程 Java语言支持多线程 说明,进程和线程,进程:一个动态执行的程序。 当你运行一个程序的时候,就创建了一个用来容纳组成代码和数据空间的进程。 线程:进程中单一顺序的执行流,线程可以共享内存单元和系统资源,但不能够单独执行,必须存在于某个进程当中。,单线程

2、和多线程,单线程:一个进程中只包含一个线程,也就是说一个程序只有一条执行路线。 多线程:在单个进程中可以同时运行多个不同的线程执行不同的任务。,Java支持多线程,Java线程由以下三部分组成: 虚拟的CPU CPU所执行的代码 CPU所处理的数据 虚拟的CPU被封装在java.lang.Thread类中,有多少个线程就有多少个虚拟的CPU在同时运行,提供对多线程的支持。,说明,执行多线程的时候,Java虚拟处理机在多个线程之间轮流切换,不过每个时刻只能有一个线程在执行 。 main方法是Java的入口程序,一旦进入就启动了一个main线程 。 即使mian方法执行完最后一句, Java程序也

3、会一直等到所有线程都运行结束后才停止 。,多线程的创建,线程体 Thread子类创建线程 使用Runnable接口创建线程 比较,线程体,线程中真正执行的语句块称为线程体。 方法run()就是一个线程体,在一个线程被建立并初始化以后,系统就自动调用run( )方法。,Thread子类创建线程,继承Thread类并重写其中的方法run( )来实 现,把线程实现的代码写到run( )方法中,线 程从run( )方法开始执行,直到执行完最后一 行代码或线程消亡。 请看例子,使用Runnable接口,利用Runnable接口可以让其他类的子类实现多线程的创建,这是利用继承Thread类的方法无法办到的

4、。 采用该方式来创建线程,还必须引用Thread 类的构造方法,把采用Runnable接口类的对象作为参数封装到线程对象当中。 请看例子,比较,使用子类直接继承Thread类的方法创建线程,可以在子类中增加新的成员变量和新的成员函数,使得线程具有新的属性和功能,还可以直接操作线程,但由于java中不支持多继承,因此Thread子类不能扩展其他的类; 利用Runnable接口,线程的创建可以从其它类继承,使得代码和数据分开,不过需要使用Thread对象来操纵线程。,线程的生命期及其状态,线程的状态 线程的状态转换图 与线程状态有关的Thread类方法,线程的状态,线程的生命期是指从线程被创建开始

5、到死亡的过程。通常包括以下5种状态: 新建状态 就绪状态 运行状态 阻塞状态 死亡状态,新建状态,当用Thread类或其子类创建了线程对象时,该线程对象就处于新建状态,系统为该新线程分配了内存空间和其他资源。,就绪状态,线程就排队等待CPU调度的状态。有三种情况使得线程进入就绪状态: 新建状态的线程被启动,但不具备运行的条件; 处于正在运行的线程时间片结束或调用yield()方 法; 被阻塞的线程引起阻塞的因素消除了,进入排队 队列等待CPU的调度。,运行状态,当线程被调度获得了CPU控制权的时候,就进入了运行状态。线程在运行状态时,会调用本对象的run()方法 。,阻塞状态,当运行的线程被人

6、为挂起或由于某些操作使得资源不满足的时候,暂时终止自己的运行,让出CPU,进入阻塞状态。 有下面4种原因使得线程进入阻塞状态: 调用了wait()方法 调用了sleep()方法 调用了suspend()方法 由于输入输出流而引起阻塞,死亡状态,线程的run()方法执行完所有的任务正常地结束; 线程被stop()方法强制地终止。,线程消亡有两种情况:,线程的状态转换图,与线程状态有关的Thread类方法,线程状态的判断 线程的新建和启动 线程的阻塞和唤醒 线程的停止,线程状态的判断,isAlive()方法判断线程是否在运行,如果是,返回true,否则返回false。不管是线程未开启还是结束,is

7、Alive()方法都会返回false。,线程的新建和启动,通过new Thread()方法可以创建出一个线程对象,不过此时Java虚拟机并不知道它,因此,我们需要通过start()方法来启动它。 请看例子,线程的阻塞和唤醒,wait()方法 sleep()方法 join()方法 yield()方法 suspend ()方法,wait()方法,public final void wait() public final void wait(long time) public final void wait(long time,int args) 调用wait()方法的线程必须通过调用notify(

8、)方法来唤醒它。方法定义如下: public final void notify() public final void notifyAll() 其中,notify()方法是随机唤醒一个等待的线程 notifyAll()方法是唤醒所有等待的线程。,sleep()方法,public static void sleep(long time) public static void sleep(long time,int args),比较 Thread的sleep()方法使线程进入睡眠状态,但它并不会释放线程持有的资源,不能被其他资源唤醒,不过睡眠一段时间会自动醒过来,而wait()方法让线程进入等待

9、状态的同时也释放了持有的资源,能被其他资源唤醒。,join()方法,join()方法是指线程的联合,即在一个线程运行过程中,若其他线程调用了join()方法与当前运行的线程联合,运行的线程会立刻阻塞,直到与它联合的线程运行完毕后才重新进入就绪状态,等待CPU的调度。 public final void join() public final void join(long time) public final void join(long time,int args) 请看例子,yield()方法,yield()方法是释放当前CPU的控制权。当线程调用yield()方法的时候,若系统中存在相同优

10、先级的线程,线程将立刻停下调用其它优先级相同的线程,若不存在相同优先级的线程,那么yield()方法将不产生任何效果,当前调用的线程将继续运行。,suspend ()方法,在Java2之前,可以利用suspend()和resume()方法对线程挂起和恢复,但这两个方法可能会导致死锁,因此现在不提倡使用。 Java语言建议采用wait()和notify()来代替suspend()和resume ()方法。,线程的停止,使用stop()方法停止一个线程,不过stop()方法是不安全的,停止一个线程可能会使线程发生死锁,所以现在不推荐使用了。Java建议使用其他的方法来代替stop()方法,比如可以

11、把当前线程对象设置为空,或者为线程类设置一个布尔标志,定期地检测该标志是否为真,如要停止一个线程,就把该布尔标志设置为true。 请看例子,线程的同步,示例 Synchronized方法 方法同步 对象同步 饿死和死锁,示例,假设有两个线程Thread1和Thread2同时要访问变量num,线程Thread1对其进行num=num+1的操作,线程Thread2是把num加一后的值附给一个变量data,而线程Thread1的加操作需要三步来执行: 把num装入寄存器; 对该寄存器加1; 把寄存器内容写回num 假设在第一步和第二步完成后该线程被切换,如果此时线程Thread2具有更高优先级线程,

12、线程Thread2占用了CPU,紧接着就把num值赋给data,虽然num的值已加1,但是还在寄存器中,于是出现了数据不一致性。为解决共享数据的操作问题,Java语言中引入线程同步的概念。,Synchronized方法,Java语言中使用关键字synchronized来实现线程的同步。当一个方法或对象使用Synchronized关键字声明的时候,系统就为其设置一特殊的内部标记,称为锁,当一个线程调用该方法或对象的时候,系统都会检查锁是否已经给其他线程了,如果没有,系统就把该锁给它,如果该锁已经被其他线程占用,那么该线程就要等到锁被释放了,才能访问该方法。有时我们需要暂时释放锁,使得其他线程可以

13、调用同步方法,这就可以利用wait()方法来实现。wait()方法可以使持有锁的线程暂时释放锁,直到有其他线程通过notify方法使它重新获得该锁。,方法同步,一个类中任何方法都可以设计成为synchronized方法。我们来看一个例子: 有两个线程:Company和Staff,职员Staff有一个账户,公司每个月把工资存到该职员的账户上,该职员可以从账户上领取工资,职员每次要等Company线程把钱存到账户后,才能从账户上领取工资,这就涉及线程的同步机制。 请看例子,对象同步,synchronized 除了像上面讲的放在方法前面表示整个方法为同步方法外,还可以放在对象前面限制一段代码的执行,

14、实现对象同步。 请看例子 另一种方法是使用Object对象来上锁 请看例子,饿死和死锁,饿死 :如果一个线程执行很长时间,一直占着CPU资源,而使 得其它线程不能运行,就可能导致“饿死”。 死锁:如果两个或多个线程都在互相等待对方持有的锁,那么 这些线程都进入阻塞状态,永远等待下去,无法执行,程序就出现了死锁。 请看例子,线程的优先级和调度,线程的优先级 线程的调度,线程的优先级,Java中,给每个线程赋一个从1到10整数值来表示多线程优先级,优先级决定了线程获得CPU调度执行的优先程度。 Thread.MIN_PRIORITY(通常为1)的优先级最小; Thread.MAX_PRIORITY

15、(通常为10)优先级最高, NORM_PRIORITY表示缺省优先级,默认值为5。 优先级的操作 获得线程的优先级 int getPriority(); 改变线程的优先级 void setPriority(int newPriority) 请看例子,线程的调度,Java调度器调度遵循以下原则: 优先级高的线程比优先级低的线程线程先调度。 优先级相等的线程按照排队队列的顺序进行调度。 先到队列的线程先被调度。 在时间片方式下,优先级高的线程要等优先级低的线程时间片运行完毕才能被调度。 在抢占式调度方式下,优先级高的线程可以立刻获得CPU的控制权。 由于优先级低的线程只有等优先级高的线程运行完毕或

16、优先级高的线程进入阻塞状态才有机会运行,为了让优先级低的线程也有机会运行,通常会不时让优先级高的线程进入睡眠或等待状态,让出CPU的控制权。,守护线程,setDaemon(boolean on)方法是把调用该方法的线程设置为守护线程。线程默认为非守护线程,也就是用户线程。当我们把一个线程设置为守护线程时,守护线程在所有非守护线程运行完毕后它的run()方法还没执行结束,守护线程也会立刻结束。把一个线程设置为守护线程方式如下: thread. setDaemon(true) 请看例子,线程组,入门 线程组的构造 ThreadGroup类 的一些方法,入门,线程组是把多个线程集成到一个对象里并可以同时管理这些线程。 每个线程组都拥有一个名字以及与它相关的一些属性。每个线程都属于一个线程组。 在线程创建时,可以将线程放在某个指定的线程组中,也可以将它放在一个默认的线程组。 若创建线程而不明确指定属于哪个组,它们就会自动归属于系统默认的线程组。 一旦线程加入了某个线程组,它将一直是这个线程组的成员,而不能改变到其他的组。,线程组的构造,以下三种Thread类的构造方法实现线程创建的同时指定

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号