《08多线程并发编程电子课件 Java程序设计案例教程.pptx》由会员分享,可在线阅读,更多相关《08多线程并发编程电子课件 Java程序设计案例教程.pptx(36页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、模块8 多线程并发编程学习目标01掌握有关线程的基本概念。02掌握通过创建Thread类的子类和通过实现Runnable接口实现多线程的方法。03了解线程的状态和生命周期。05了解线程同步的概念。04了解线程优先级和线程调度。技能目标1.能够在MyEclipse IDE中编程创建Thread类的子类实现多线程。2.能够在MyEclipse IDE中编程实现Runnable接口实现多线程。3.能够在MyEclipse IDE中编程实现线程同步。8.1 回顾与思考多线程是Java的重要特性之一。如果一个程序是单线程的,那么,任何时刻都只有一个执行点。这种单线程执行方法使系统的运行效率偏低,而且,由
2、于必须依靠中断来处理输入/输出,所以,当出现频繁输入/输出或有优先级较低的中断请求时,实时性就变得很差。多线程系统可以避免这个缺点。所谓多线程,就是通过系统的调用使几个具有不同功能的程序流即线程并行运行。多线程可以实现同一时刻执行多个程序,使程序执行的效率变得更高。浏览器就是一个典型的多线程例子。在浏览器中可以一边下载文件,一边播放音频和视频,一边打印文档等。多线程是实现并发的一种有效手段。Java在平台上提供了对多线程的有效支持,利用语言和运行支持系统提供的复杂同步机制,同时还确保了线程的安全性。8.2 线程的使用8.2.1 线程的基本结构1.继承Thread类(1)Thread类。Thre
3、ad类是负责向其他类提供线程功能的最主要的类,为了向一个类增加线程功能,可以简单地从Thread类派生一个类,并重写run()方法。run()方法是线程发生的地方,它常常被称为线程体。Thread类的常用构造方法及成员方法见表8-1。表8-1 Thread类的常用构造方法及成员方法8.2 线程的使用8.2.1 线程的基本结构1.继承Thread类(2)用创建Thread类的子类实现多线程。若用这种方法实现多线程,用户须在程序中创建Thread类的子类,并在子类中重写Thread类的run()方法来定义线程体以实现线程的具体功能,然后创建该子类的对象以创建线程,当用户创建的线程调用start()
4、方法启动时,run()方法将被系统自动执行。8.2 线程的使用8.2.1 线程的基本结构1.继承Thread类【例8-1】通过定义Thread类的子类实现多线程。文件名为Example8_1.java,其代码如下。其代码见P159-160。运行结果如下。8.2 线程的使用8.2.1 线程的基本结构2.用实现Runnable接口实现多线程Runnable接口只定义了一个run()方法,该方法是一个抽象方法,所有实现Runnable接口的类都必须具体实现这个方法,为它提供方法体并定义具体操作。Runnable接口中的run()方法与Thread类中的run()方法一样,能被系统自动识别执行。8.2
5、 线程的使用8.2.1 线程的基本结构2.用实现Runnable接口实现多线程(1)创建实现Runnable接口的类ClassName。基本语法格式如下。(2)创建ClassName类的对象。基本语法格式如下。8.2 线程的使用8.2.1 线程的基本结构2.用实现Runnable接口实现多线程(3)用带有Runnable参数的Thread类构造方法创建线程对象,对象RunnableObject作为构造方法的参数,作为新建线程的目标对象为线程提供run()方法。例如,用表8-1中列出的构造方法Thread(Runnable target)创建线程对象。Thread类中除了上述构造方法带有Runn
6、able参数外,还有下面3个构造方法也带有Runnable参数。8.2 线程的使用8.2.1 线程的基本结构2.用实现Runnable接口实现多线程(4)启动定义的线程。基本语法格式如下。与创建Thread类的子类实现多线程相比,通过Runnable接口实现多线程方法为线程的创建提供了更大的灵活性。由于Java语言不允许多重继承,如果采用创建Thread类的子类的方法创建新线程类,则该类不能再继承其他类,这就限制了程序的功能。而后一种方法却没有这方面的顾虑。8.2 线程的使用8.2.1 线程的基本结构2.用实现Runnable接口实现多线程【例8-2】通过实现Runnable接口实现多线程。文
7、件名为Example8_2.java,其代码如下。其代码见P162-163。运行结果如下。我正在工作!我正在休息,喝咖啡!我正在工作!我正在工作!我正在工作!我正在工作!工作顺利完成!8.2 线程的使用8.2.1 线程的基本结构2.用实现Runnable接口实现多线程【例8-2】通过实现Runnable接口实现多线程。文件名为Example8_2.java,其代码如下。其代码见P162-163。运行结果如下。我正在工作!我正在休息,喝咖啡!我正在工作!我正在工作!我正在工作!我正在工作!工作顺利完成!8.2 线程的使用8.2.2 线程的状态及调度每个Java程序都有一个默认的主线程。对于应用程
8、序,主线程是main()方法执行的路径。对于Applet,主线程指挥浏览器加载并执行Java小程序。为实现多线程,必须在主线程中创建新的线程对象。Java线程是通过Java.lang包中的Thread类来实现的。可通过创建一个Thread类的对象来产生一个新的线程。一个线程一旦产生,它就处于生命周期中的某一种状态。线程的状态表示了线程正在进行的活动及能够完成的任务。图8-1描述了线程的生命周期及其状态转换。8.2 线程的使用8.2.2 线程的状态及调度图8-1 线程的生命周期及其状态转换从图8-1中可以看出,在一个线程从创建到消亡的整个生命周期中,总是处于下面5个状态中的某个状态。8.2 线程
9、的使用8.2.2 线程的状态及调度1.新建状态通过new关键字创建一个Thread类或其子类的线程对象时,该线程对象处于新建状态。创建一个新的线程对象可以用下面的语句实现:该语句是最简单的创建线程语句,但该语句创建的线程是一个空的线程对象,系统还未对这个线程分配任何资源。8.2 线程的使用8.2.2 线程的状态及调度2.就绪状态就绪状态又可称为可运行状态。处于新建状态的线程可通过调用start()方法来启动。start()方法产生了线程运行所需要的系统资源。启动后的线程将进入线程就绪队列排队等待CPU服务,此时线程已经具备了运行的条件,一旦获得CPU等资源,线程就可以脱离创建它的主线程而独立运
10、行。3.运行状态当处于就绪状态的线程被调度并获得CPU资源时,线程就进入运行状态。每个线程对象都有一个重要的run()方法,run()方法定义了该线程的操作和功能。当线程对象被调度执行时,它将自动调用其run()方法并从第一条语句开始顺次执行。8.2 线程的使用8.2.2 线程的状态及调度4.阻塞状态阻塞状态又称为不可运行状态。当发生下列情况之一时,线程就进入阻塞状态。(1)等待输入/输出操作完成。(2)线程调用wait()方法等待一个条件变量。(3)调用了该线程的sleep()休眠方法。(4)调用了suspend()悬挂方法。8.2 线程的使用8.2.2 线程的状态及调度5.消亡状态消亡状态
11、又称死亡状态。当调用run()方法结束后,线程就进入消亡状态,这是线程的正常消亡。另外,线程还可能被提前强制性消亡。不管何种情况,处于消亡状态的线程都不具有继续运行的能力。8.2 线程的使用8.2.3 线程的控制多线程编程对于许多程序员来说是一件棘手的事,特别是当运行的线程数量很多时,控制这些线程相当困难。Java提供了线程组(java.lang.ThreadGroup类)来控制线程,使同时改变大量线程的运行状态成为可能。在创建线程之前,可以创建一个ThreadGroup对象,下面的代码片段是创建一个线程组,并在其中加入两个线程的例子。当线程组被创建以后,每一个线程被创建并传递给ThreadG
12、roup对象,成为线程组中的成员。8.2 线程的使用8.2.3 线程的控制【例8-3】用线程组控制线程。文件名为Example8_3.java,其代码如下。其代码见P166-167。某次运行的结果如下。其代码见P167-168。8.3 线程的管理8.3.1 优先级Java中每个线程都有一个优先级,线程调度器根据优先级的高低决定当前哪个线程先执行。优先级高的线程先执行,优先级低的线程后执行。这样就可以为任务较紧急的重要线程设置较高的优先级,在就绪队列中排在前面;反之,则设置较低的优先级,等到优先级高的线程执行结束后才被执行,让情况紧急的线程首先得到调度。但若线程优先级相同,则遵循队列的“先进先出
13、”原则,即先到的线程先获得CPU资源执行。8.3 线程的管理8.3.1 优先级在Java中,线程的优先级是用数字来表示的,其取值范围为110。另外,Thread类提供3个有关线程优先级的静态属性,见表8-2。表8-2 Thread类定义的静态属性8.3 线程的管理8.3.1 优先级当一个在就绪队列中排队的线程获得CPU资源而转入运行状态后,则称这个线程被调度。线程的调度遵循优先级基础上的抢先策略。抢先策略是指以下几个方面。(1)若一个比当前活动线程优先级更高的线程进入就绪状态,则停止当前活动线程的执行,当前活动线程转入阻塞状态,插入就绪队列中重新等待调度,而优先级高的线程转入运行状态,成为活动
14、线程。(2)若一个比当前活动线程优先级低的线程进入就绪状态,则当前活动线程不停止继续执行,刚进入就绪状态的线程在就绪队列中等待调度。(3)若一个与当前活动线程优先级相同的线程进入就绪状态,则遵循“先到先服务”的原则。8.3 线程的管理8.3.2 同步线程同步的基本思想是协调各线程对共享资源的使用,避免多个线程在某段时间内对同一资源的访问,这个资源可以是数据、代码、设备等。Java通过关键字synchronized来表明被同步的资源,即给资源加“锁”,这个“锁”被称为信号锁。当某个资源被synchronized关键字修饰时,系统在运行时都会分配给它一个信号锁,表明该资源在同一时刻只能由一个线程访
15、问。但是,处理线程同步仅仅定义信号锁是不够的,Java中专门设计了以下3个方法与信号锁配合使用。8.3 线程的管理8.3.2 同步01public final void wait()(等待方法)该方法是一个最终方法,不能被重写,只能在同步方法中被调用。执行该方法会将当前正在运行的线程悬挂,释放所占用的资源,从运行状态转入阻塞状态,进入wait队列等待被唤醒。02 public final void notify()(唤醒方法)该方法也是一个最终方法,不能被重写,只能在同步方法中被调用。执行该方法将唤醒wait队列中优先级最高的一个线程,占有资源运行。8.3 线程的管理8.3.2 同步03pub
16、lic final void notifyAll()(唤醒所有方法)除了notify()方法以外,Java还设计了notifyAll()方法。它的作用与notify()方法相似,不过它是唤醒wait队列中所有的线程。wait()、notify()和notifyAll()3种方法必须在同步方法中被调用。因此,它们只能出现在synchronized作用的范围内。8.3 线程的管理8.3.2 同步在Java中,用synchronized表示同步有两种形式:同步代码块和同步方法。(1)同步代码块。其基本语法格式如下。其中,someObject代表当前对象。当程序执行到synchronized设定的同步
17、化区块时,锁定当前对象,单独执行该同步化区块。8.3 线程的管理8.3.2 同步在Java中,用synchronized表示同步有两种形式:同步代码块和同步方法。(2)同步方法。其基本语法格式如下。在调用同步方法的线程执行结束前,其他调用该同步方法的线程都会被阻塞。8.3 线程的管理8.3.2 同步【例8-4】生产者-消费者模型演示。文件名为Example8_4.java,其代码如下。其代码见P171-174。以下是某次运行结果。其代码见P174-175。8.4 小结进程是程序从代码加载、执行到执行完毕的一个完整的动态执行过程。同时运行多个程序(任务)时称为多进程(多任务)。进程在执行过程中可
18、形成多条执行线索,每条线索称为一个线程。程序执行时,只有一条路线时称为单线程。程序按几条不同的执行路线共同工作时称为多线程。Java语言的一个重要功能特点就是内置对多线程的支持。Java使用Thread类及其子类的对象来表示线程,线程的生命周期包括新建、就绪、运行、阻塞、死亡等状态。多线程系统给就绪队列中的每个线程自动分配线程的优先级,任务较重要的线程的优先级就较高;反之,则较低。优先级相同的线程遵循“先到先服务”原则。8.5 习题1.选择题(1)以下说法正确的是()。A.在创建Thread类的子类的过程中不能重写run()方法B.在Java应用程序中,用户无须引用run()方法C.sleep
19、()方法和yield()方法都可实现暂时停止一个线程的执行,两者的机理类似,没有太大区别D.多线程就是指多个程序在同时运行(2)以下有关线程状态之间的转换,转换途径合理的是()。A.新建状态运行状态 B.阻塞状态运行状态C.阻塞状态就绪状态 D.阻塞状态死亡状态8.5 习题1.选择题(3)采用()方法可将被悬挂的线程恢复至运行状态。A.notify()B.start()C.run()D.resume()(4)Java中声明同步化方法所使用的关键字是()。A.switch B.staticC.super D.synchronized2.用多线程求解从1累加到1 000。提示:设计两个线程,一个线
20、程计算从1累加到500,另一个线程计算从501累加到1 000,用join()方法协调这两个线程。8.5 习题3.编程实现每隔1秒输出“南京交通职业技术学院”中的一个字符。运行结果如下。4.以下程序代码运行后弹出一个窗口显示当前的时钟,如图8-2所示,补充完整空缺的代码。图8-2 习题4运行结果其代码见P177-178。8.6上机实践1.用继承Thread类的方法编程实现每隔1秒钟向控制台输出自然数累加的结果,加到20结束。2.用实现Runnable接口的方法编程实现每隔1秒钟向控制台输出自然数累加的结果,加到20结束。3.仔细阅读并分析下列程序代码,上机运行后有问题吗?为什么?4.修改上机实践3的代码,使运行结果合理。其代码见P179-181。谢谢观看!