Java语言程序设计第08章.ppt
《Java语言程序设计第08章.ppt》由会员分享,可在线阅读,更多相关《Java语言程序设计第08章.ppt(24页珍藏版)》请在三一办公上搜索。
1、第8章 多线程编程,支持多线程编程是Java语言的又一大特色。多线程是相对于进程或单线程而言的,它具有并发性、执行效率高的特点。本章将对Java中的多线程编程作初步介绍。,8.1 多线程编程概述8.2 线程的创建8.3 线程的优先级8.4 线程同步8.5 线程间通信8.6 线程的控制,Return,8.1 多线程编程概述,本节介绍多线程编程的基础知识,包括多线程的基本概念、Java的线程模型(线程优先级、同步性、消息传递)等方面的内容。,8.1.1 什么是多线程8.1.2 Java线程模型,Return,8.1.1 什么是多线程,同其他大多数编程语言不同,Java内置支持多线程编程(multi
2、threaded programming)。多线程程序包含两条或两条以上并发运行的部分,把程序中每个这样的部分都叫作一个线程(thread)。每个线程都有独立的执行路径,因此多线程是多任务处理的一种特殊形式。读者可能知道多任务处理,它实际上被所有的现代操作系统所支持。然而,多任务处理有两种截然不同的类型:基于进程的和基于线程的。搞清楚两者的区别是很重要的。对大多数读者来说,基于进程的多任务处理是更熟悉的形式。进程(process)本质上是一个执行的程序。因此基于进程的多任务处理的特点是允许你的计算机同时运行两个或更多的程序。举例来说,基于进程的多任务处理使你在运用文本编辑器的时候可以同时运行J
3、ava编译器。在基于进程的多任务处理中,程序是调度程序所分派的最小代码单位。而在基于线程(thread-based)的多任务处理环境中,线程是最小的执行单位。这意味着一个程序可以同时执行两个或者多个任务的功能。例如,一个文本编辑器可以在打印的同时格式化文本。所以,多进程程序处理“大图片”,而多线程程序处理细节问题。,Return,多线程程序比多进程程序需要更少的管理费用。进程是重量级的任务,需要分配给它们独立的地址空间。进程间通信是昂贵和受限的。进程间的转换也是很需要花费的。另一方面,线程是轻量级的选手。它们共享相同的地址空间并且共同分享同一个进程。线程间通信是便宜的,线程间的转换也是低成本的
4、。当Java程序使用多进程任务处理环境时,多进程程序不受Java的控制,而多线程则受Java控制。多线程可帮助你编写出CPU最大利用率的高效程序,使得空闲时间保持最低。这对Java运行的交互式的网络互连环境是至关重要的,因为空闲时间是公共的。例如,网络的数据传输速率远低于计算机处理能力,而本地文件系统资源的读写速度也远低于CPU的处理能力。当然,用户输入也比计算机慢很多。在传统的单线程环境中,程序必须等待每一个这样的任务完成以后才能执行下一步尽管CPU有很多空闲时间。多线程使你能够获得并充分利用这些空闲时间。,8.1.2 Java线程模型,Java运行系统在很多方面依赖于线程,所有的类库设计都
5、考虑到多线程。实际上,Java使用线程来使整个环境异步。这有利于通过防止CPU循环的浪费来减少无效部分。为更好地理解多线程环境的优势,我们可以将它与它的对照物相比较。单线程系统的处理途径是使用一种叫作轮询的事件循环方法。在该模型中,单线程控制在一无限循环中运行,轮询一个事件序列来决定下一步做什么。一旦轮询装置返回信号表明已准备好读取网络文件,事件循环调度控制管理到适当的事件处理程序。直到事件处理程序返回,系统中没有其他事件发生。这就浪费了CPU时间。这导致了程序的一部分独占了系统,阻止了其他事件的执行。总的来说,单线程环境,当一个线程因为等待资源时阻塞(block,挂起执行),整个程序停止运行
6、。,Java多线程的优点就在于取消了主循环/轮询机制。一个线程可以暂停而不影响程序的其他部分。例如,当一个线程从网络读取数据或等待用户输入时产生的空闲时间可以被利用到其他地方。多线程允许活的循环在每一帧间隙中沉睡一秒而不暂停整个系统。在Java程序中出现线程阻塞,仅有一个线程暂停,其他线程继续运行。线程存在多种状态。线程可以正在运行(running),只要获得了CPU时间它就可以运行;运行的线程可以被挂起(suspend),并临时中断它的执行;一个挂起的线程可以被恢复(resume),允许它从停止的地方继续运行;一个线程可以在等待资源时被阻塞(block);在任何时候,线程可以被终止(term
7、inate),这将立即中断运行。一旦终止,线程不能被恢复。线程的各状态间关系见教材P190页图8-1所示。,下面简要介绍与Java线程相关的几个概念,Java给每个线程安排优先级以决定与其他线程比较时该如何对待该线程。线程优先级是详细说明线程间优先关系的整数。作为绝对值,优先级是毫无意义的;当只有一个线程时,优先级高的线程并不比优先级低的线程运行的快。相反,线程的优先级是用来决定何时从一个运行的线程切换到另一个。这叫“上下文转换”(context switch)。决定上下文转换发生的规则很简单:l线程可以自动放弃控制。在I/O未决定的情况下,睡眠或阻塞由明确的让步来完成。在这种假定下,所有其他
8、的线程被检测,准备运行的最高优先级线程被授予CPU。l线程可以被高优先级的线程抢占。在这种情况下,低优先级线程不主动放弃,处理器只是被先占无论它正在干什么处理器被高优先级的线程占据。基本上,一旦高优先级线程要运行,它就执行。这叫做有优先级的多任务处理。当两个相同优先级的线程竞争CPU周期时,情形有一点复杂。对于Windows这样的操作系统,等优先级的线程是在循环模式下自动划分时间的。对于其他一些非Windows操作系统而,如Solaris 2.x,等优先级线程相对于它们的对等体自动放弃。如果不这样,其他的线程就不会运行。,1线程优先级,2同步性,由于多线程在程序中引入了一个异步行为,故在需要的
9、时候必须有加强同步性的方法。举例来说,如果你希望两个线程相互通信并共享一个复杂的数据结构,例如链表序列,就需要某些方法来确保它们没有相互冲突。也就是说,你必须防止一个线程写入数据而另一个线程正在读取链表中的数据。为此,Java在进程间同步性的老模式基础上实行了另外的一种方法:管程(monitor)。管程是一种由首先定义的控制机制。你可以把管程想象成一个仅控制一个线程的小盒子。一旦线程进入管程,所有线程必须等待直到该线程退出了管程。用这种方法,管程可以用来防止共享的资源被多个线程操纵。很多多线程系统将管程作为程序必须明确的引用和操作的对象。但Java提供一个清晰的解决方案,不提供“Monitor
10、”类;相反,每个对象都拥有自己的隐式管程,当对象的同步方法被调用时管程自动载入。一旦一个线程包含在一个同步方法中,没有其他线程可以调用相同对象的同步方法。这就使你可以编写非常清晰和简洁的多线程代码,因为同步支持是语言内置的。,3消息传递,当把程序分成若干线程后,就要定义各线程之间的联系。用大多数其他语言规划时必须依赖于操作系统来确立线程间通信,这样当然要增加花费。然而,Java提供了多线程间谈话清洁的、低成本的途径通过调用所有对象都有的预先确定的方法。Java的消息传递系统允许一个线程进入一个对象的一个同步方法,然后在那里等待,一直等到其他线程明确通知它出来。,Return,Java的多线程系
11、统建立于Thread类、方法以及共伴接口Runnable基础上。Thread类封装了线程的执行。既然不能直接引用运行着的线程的状态,就要通过它的代理处理它。于是Thread 实例产生了。为创建一个新的线程,程序中必须扩展Thread 或实现Runnable接口。Thread类定义了好几种方法来帮助管理线程,见教材P192页表8-1中所列。,4Thread类和Runnable接口,8.2 线程的创建,本节介绍在Java中如何创建线程。主要内容包括主线程、多线程的创建、相关方法的使用等。,8.2.1 关于主线程8.2.2 创建一个线程8.2.3 创建多线程8.2.4 使用isAlive()和joi
12、n(),Return,8.2.1 关于主线程,当Java程序启动时,一个线程立刻运行,该线程通常就叫做程序的主线程(main thread),因为它是程序开始时就执行的。主线程的重要性主要体现在两方面:l它是产生其他子线程的线程;l通常它必须最后完成执行,因为它执行各种关闭动作。尽管主线程在程序启动时自动创建,但它可以由一个Thread对象控制。为此,必须调用方法currentThread()获得它的一个引用,currentThread()是Thread类的公有的静态成员。它的一般形式如下 static Thread currentThread()该方法返回一个调用它的线程的引用。一旦获得主线
13、程的引用,就可以像控制其他线程那样控制主线程。下面我们考察一下教材P192193页的程序代码。在上面的程序中,当前线程(当然是主线程)的引用通过调用currentThread()获得,该引用保存在局部变量t中。然后,程序显示了线程的信息。接着,程序调用setName()改变线程的内部名称,线程信息又被显示。然后,一个循环数从5开始递减,每数一次暂停一秒。暂停是由sleep()方法来完成的,sleep()语句明确规定延迟时间是1毫秒。请读者注意循环外的try/catch块。Thread类的sleep()方法可能引发一个InterruptedException异常,这种情形会在其他线程想要打搅沉睡
14、线程时发生。本例只是打印了它是否被打断的消息。在实际的程序中,必须灵活处理此类问题。,Return,8.2.2 创建一个线程,大多数情况,通过实例化一个Thread对象来创建一个线程。Java定义了两种方式:l实现Runnable 接口;l以继承Thread类的方式。,创建线程最简单的方法就是创建一个实现Runnable 接口的类,Runnable抽象了一个执行代码单元。可以通过实现Runnable接口的方法创建每一个对象的线程。为实现 Runnable 接口,一个类仅需实现一个run()的简单方法,该方法声明如下:public void run()在run()中,可以定义代码来构建新的线程。
15、重要的是:run()方法能够像主线程那样调用其他方法,引用其他类,声明变量。仅有的不同是:run()在程序中确立另一个并发的线程执行入口。当run()返回时,该线程结束。在已经创建了实现Runnable接口的类以后,需要在类内部实例化一个Thread类的对象。Thread 类定义了好几种构造函数。我们会用到的如下:Thread(Runnable threadOb,String threadName)在该构造函数中,threadOb是一个实现Runnable接口类的实例。这定义了线程执行的起点,新线程的名称由threadName定义。建立新的线程后,它并不运行直到调用其start()方法,该方法
16、在Thread 类中定义。从本质上讲,start()执行的是一个对run()的调用。start()方法声明如下:void start(),下面我们分别对这两种方法进行介绍:,1实现Runnable接口,2扩展Thread,创建线程的另一个途径是创建一个新类来扩展Thread类,然后再创建该类的实例。当一个类继承Thread时,它必须重载run()方法,这个run()方法是新线程的入口。同时,它也必须调用start()方法去启动新线程执行。,Return,到这里,读者可能会奇怪为什么Java有两种创建子线程的方法,哪一种更好呢。所有的问题都归于一点。Thread类定义了多种方法可以被派生类重载。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 语言程序设计 08
链接地址:https://www.31ppt.com/p-6510219.html