javake课件第8章Java线程.ppt

上传人:max****ui 文档编号:6358464 上传时间:2020-02-23 格式:PPT 页数:60 大小:405.50KB
返回 下载 相关 举报
javake课件第8章Java线程.ppt_第1页
第1页 / 共60页
javake课件第8章Java线程.ppt_第2页
第2页 / 共60页
javake课件第8章Java线程.ppt_第3页
第3页 / 共60页
点击查看更多>>
资源描述
第8章Java线程 学习导读本章将介绍Java线程编程技术 以及多线程的同步和互斥 第8章Java线程 线程基础线程的生命多线程共享数据多线程的互斥和同步本章小结 线程的概念 多任务 计算机在看上去几乎同一时间内运行多个程序 多线程 单个程序内部也可以在同一时间进行多种运算 一个线程是一个程序内部的顺序控制流 不是程序 自己本身不能运行 必须在程序中运行 如何在一个程序内部实现多个线程 线程和进程每个进程都有独立的代码和数据空间 进程上下文 进程切换的开销大 线程 轻量的进程 同一类线程共享代码和数据空间 每个线程有独立的运行栈和程序计数器 PC 线程切换的开销小 多进程 在操作系统中 能同时运行多个任务 程序 多线程 在同一应用程序中 有多个顺序流同时执行 线程的概念模型 虚拟的CPU 封装在java lang Thread类中 CPU所执行的代码 传递给Thread类 CPU所处理的数据 传递给Thread类 线程体 Java的线程是通过java lang Thread类来实现的 当我们生成一个Thread类或者它的子类的对象后 一个新的线程就诞生了 每个线程都是通过某个特定Thread对象的方法run 来完成其操作的 方法run 称为线程体 线程的状态 唤醒 挂起 睡眠或等待 创建状态 newThread ThreadmyThread newMyThreadClass 可运行状态 Runnable 非运行态ThreadmyThread newMyThreadClass myThread start 这一状态并不是运行中状态 Running 因为也许线程并未真正执行 只有被调度执行时 才真正处于运行状态 不可运行状态 NotRunnable Blocked 调用了sleep 方法 此时线程的run 方法将中断执行调用了suspend 方法 挂起线程 不推荐使用为等候一个条件变量 线程调用wait 方法 I O处发生线程阻塞 I O阻塞对于上面四种情况 都有可以返回可运行态的方法与之对应 1 sleep 方法中的参数为休息时间 单位为毫秒 时间过去后 线程即为可运行的 不是运行态 需再次被调度2 一个线程调用suspend 方法后 只能有其它线程调用它的resume 方法恢复 3 如果一个线程等待条件变量 如果要停止等待 需要条件变量所在的对象调用notify 或者notifyAll 方法 4 特定的I O指令完成 结束不可运行状态 死亡状态 Dead 线程的终止一般可通过两种方法实现 自然撤销 线程执行完 或是被停止 调用stop 方法 不推荐使用 自然撤销是线程的run 方法正常退出 如下面的程序 publicvoidrun inti 0 for i 0 i 10 i System out println i t start t是一个线程 省略了一些语句t stop 调用stop 终止线程 其它注意事项1 非法状态处理对于任何状态 如果调用的方法和状态不符 都会引起非法状态处理 例如 线程刚创建后 只能调用start 或者stop 方法 如果调用其它方法就会引起非法状态处理 2 isAlive 方法在类Thread中提供了方法isAlive 如果线程已经启动 start 但是未终止 dead 返回true 反之 返回false 表示该线程未启动 或者已终止 如果isAlive 方法返回true 不能区分是可运行态 runnable 还是不可运行态 notrunnable 顺序执行 单线程 程序 publicclassSequentialDemo publicstaticvoidmain String args newSequential C run newSequential D run classSequential Stringname null publicSequential Stringn name n publicvoidrun for inti 0 i 5 i try 睡眠一段随机时间Thread sleep long Math random 1000 catch InterruptedExceptione e printStackTrace System out print name 每次总输出结果 CCCCCDDDDD 线程体的构造 1 publicThread 创建一个线程对象 2 publicThread Runnabletarget 参数target的run 方法将被线程对象调用 3 publicThread Stringname 线程的名称 4 publicThread Runnabletarget Stringname 5 publicThread ThreadGroupgroup Runnabletarget 6 publicThread ThreadGroupgroup Stringname 7 publicThread ThreadGroupgroup Runnabletarget Stringname group指明线程所在的组 可以把很多线程加在一个组里面 进行集中控制 target是执行线程体的目标对象 生成这个对象的类 实现了Runnable接口 其中包含线程体run 方法 name是线程的名称 任何实现接口Runnable的对象都可以作为一个线程的目标对象 构造线程体的两种方法 1 定义一个线程类 它继承类Thread并重写其中的方法run 2 提供一个实现接口Runnable的类作为线程的目标对象 在初始化一个Thread类或者Thread子类的线程对象时 把目标对象传递给这个线程实例 由该目标对象提供线程体run Runnable接口中只定义了一个空方法run 1 通过继承类Thread构造线程体 classSimpleThreadextendsThread publicSimpleThread Stringstr super str publicvoidrun for inti 0 i 10 i System out println i getName try sleep int Math random 1000 catch InterruptedExceptione System out println DONE getName publicclassTwoThreadsTest publicstaticvoidmain Stringargs newSimpleThread First start newSimpleThread Second start 运行结果 0First0Second1Second1First2First2Second3Second3First4First4Second5First5Second6Second 6First7First7Second8Second9Second8FirstDONE Second9FirstDONE First 2 通过接口构造线程体 例子1 classSimpleThreadimplementsRunnable publicSimpleThread Stringstr super str publicvoidrun for inti 0 i 10 i System out println i Thread currentThread getName try Thread sleep int Math random 1000 catch InterruptedExceptione 2 通过接口构造线程体 例子1 续 System out println DONE Thread currentThread getName publicclassTwoThreadsTest publicstaticvoidmain Stringargs newThread newSimpleThread First start newThread newSimpleThread Second start 例子1输出结果 0First0Second1Second2Second1First3Second4Second2First3First4First 5First5Second6First6Second7First7Second8First8Second9FirstDONE 9SecondDONE 2 通过接口构造线程体 例子2 publicclassClockextendsjava applet AppletimplementsRunnable ThreadclockThread publicvoidstart if clockThread null clockThread newThread this Clock clockThread start publicvoidrun while clockThread null repaint try clockThread sleep 1000 catch InterruptedExceptione publicvoidpaint Graphicsg Datenow newDate g drawString now getHours now getMinutes now getSeconds 5 10 publicvoidstop clockThread stop clockThread null 两种方法的比较 使用Runnable接口可以将CPU 代码和数据分开 形成清晰的模型 还可以从其他类继承 保持程序风格的一致性 使用Thread currentThread 获取当前线程进行控制 直接继承Thread类不能再从其他类继承 编写简单 可以直接操纵线程 两种构造线程方法之间的关系 线程的调度 Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程 线程调度器按照线程的优先级决定应调度哪些线程来执行 Java运行系统的线程调度算法是抢先式的 preemptive 时间片方式非时间片方式 下面几种情况下 当前线程会放弃CPU 线程调用了yield 或sleep 方法主动放弃或它的run 方法结束 由于当前线程进行I O访问 外存读写 等待用户输入等操作 导致线程阻塞 为等候一个条件变量 线程调用wait 方法 抢先式系统下 由高优先级的线程参与调度 时间片方式下 当前时间片用完 由同优先级的线程参与调度 注意 使用yield 方法只能给同优先级的线程提供执行机会 如果没有同优先级的线程处于可运行态 yield 将被忽略 线程的优先级 线程的优先级用数字来表示 范围从1到10 即Thread MIN PRIORITY 1 到Thread MAX PRIORITY 10 一个线程的缺省优先级是5 即Thread NORM PRIORITY 5 intgetPriority voidsetPriority intnewPriority classThreadTest publicstaticvoidmain Stringargs Threadt1 newMyThread T1 t1 setPriority Thread MIN PRIORITY t1 start Threadt2 newMyThread T2 t2 setPriority Thread MAX PRIORITY t2 start Threadt3 newMyThread T3 t3 setPriority Thread MAX PRIORITY t3 start classMyThreadextendsThread Stringmessage MyThread Stringmessage this message message publicvoidrun for inti 0 i 3 i System out println message getPriority 运行结果 T210T210T210T310T310T310T11T11T11 注意 并不是在所有系统中运行Java程序时都采用时间片策略调度线程 所以一个线程在空闲时应该主动放弃CPU 以使其他同优先级和低优先级的线程得到执行 基本的线程控制 终止线程线程执行完其run 方法后 会自然终止 通过调用线程的实例方法stop 来终止线程 测试线程状态可以通过Thread中的isAlive 方法来获取线程是否处于活动状态 线程由start 方法启动后 直到其被终止之间的任何时刻 都处于 Alive 状态 线程的暂停和恢复sleep 方法suspend 和resume 方法join 方法当前线程等待调用该方法的线程结束后 再恢复执行 TimerThreadtt newTimerThread 100 tt start publicvoidtimeout tt join 等待线程tt执行完后再继续往下执行 多线程的互斥与同步 多线程的互斥与同步 临界资源问题classstack intidx 0 char data newchar 6 publicvoidpush charc data idx c idx publiccharpop idx returndata idx 两个线程A和B在同时使用Stack的同一个实例对象 A正在往堆栈里push一个数据 B则要从堆栈中pop一个数据 1 操作之前data p q idx 22 A执行push中的第一个语句 将r推入堆栈 data p q r idx 2 3 A还未执行idx 语句 A的执行被B中断 B执行pop方法 返回q data p q r idx 14 A继续执行push的第二个语句 data p q r idx 2最后的结果相当于r没有入栈 产生这种问题的原因在于对共享数据访问的操作的不完整性 在Java语言中 引入了对象互斥锁的概念 来保证共享数据操作的完整性 每个对象都对应于一个可称为 互斥锁 的标记 这个标记用来保证在任一时刻 只能有一个线程访问该对象 Java运行系统允许一个线程再次取得已为自己控制的对象锁 即对象锁是可重入的 关键字synchronized来与对象的互斥锁联系 当某个对象用synchronized修饰时 表明该对象在任一时刻只能由一个线程访问 publicvoidpush charc synchronized实例方法是使用this锁去做线程的 共享互斥synchronized this data idx c idx publiccharpop synchronized this idx returndata idx synchronized除了象上面讲的放在对象前面限制一段代码的执行外 还可以放在方法声明中 表示整个方法为同步方法 方法在执行时需要获取 互斥锁 是一个原子方法 不会被外界中断 publicsynchronizedvoidpush charc 如果synchronized用在类声明中 则表明该类中的所有方法都是synchronized的 多线程的同步 同步化的堆栈类 定义了两个同步方法classSyncStack privateintindex 0 privatechar buffer newchar 6 publicsynchronizedvoidpush charc while index buffer length try 或wait 等待消费者取走数据this wait catch InterruptedExceptione 最好使用notifyAll 通知消费者可以来取 数据this notify buffer index c index publicsynchronizedcharpop while index 0 try 或wait 等待生产者生产数据this wait catch InterruptedExceptione 最好使用notifyAll 通知生产者可以再次写入 数据this notify index returnbuffer index 注意 方法notifyAll 唤醒的是由于等待notifyAll 方法所在对象 这里是SyncStack 的所有线程 被唤醒的线程会去竞争对象锁 当其中某个线程得到锁之后 其他的线程重新进入阻塞状态 而notify 方法是不安全的 因为你无法控制让哪一个线程离开阻塞队列 如果让一个不合适的线程离开等待队列 它也可能仍无法向前运行 因此建议使用notifyAll 方法 让等待队列上的所有和当前对象相关的线程离开阻塞状态 生产者 消费者问题 生产者线程classProducerimplementsRunnable SyncStacktheStack publicProducer SyncStacks theStack s 资源SyncStack 生产者 消费者 publicvoidrun charc for inti 0 i 20 i c char Math random 26 A theStack push c System out println Produced c try 当前线程中断执行run 方法 进入 阻塞状态 给其他线程以执行的机会Thread sleep int Math random 100 catch InterruptedExceptione 消费者线程classConsumerimplementsRunnable SyncStacktheStack publicConsumer SyncStacks theStack s publicvoidrun charc for inti 0 i 20 i c theStack pop System out println Consumed c try Thread sleep int Math random 1000 catch InterruptedExceptione 模拟生产者 消费者问题的主程序publicclassSyncTest publicstaticvoidmain Stringargs SyncStackstack newSyncStack Runnablesource newProducer stack Runnablesink newConsumer stack Threadt1 newThread source Threadt2 newThread sink t1 start t2 start 程序执行结果 Produced VConsumed VProduced EConsumed EProduced PProduced L Consumed LConsumed P wait notify notifyAll 1 wait nofity notifyAll必须在已经持有锁的情况下执行 所以它们只能出现在synchronized作用的范围内 这些方法都是在java lang Object中定义的 2 wait的作用 释放已持有的锁 进入wait队列 3 notify的作用 唤醒wait队列中的一个线程 并把它移入锁申请队列 4 notifyAll的作用 唤醒wait队列中的所有的线程并把它们移入锁申请队列 模拟考题 Question1 WhichofthefollowingaremethodsoftheRunnableinterface1 run2 start3 yield4 stop 模拟考题 AnswertoQuestion1 1 TheRunnableinterfacehasonlyonemethodrunthatneedstobecreatedinanyclassthatimplementsit Thestartmethodisusedtoactuallycallandstarttherunmethodexecuting 模拟考题 Question2 WhatwillhappenwhenyouattempttocompileandrunthefollowingcodepublicclassBorleyextendsThread publicstaticvoidmain Stringargv Borleyb newBorley b start publicvoidrun System out println Running 模拟考题 1 Compilationandrunbutnooutput2 Compilationandrunwiththeoutput Running 3 CompiletimeerrorwithcomplaintofnoThreadtarget4 CompiletimeerrorwithcomplaintofnoaccesstoThreadpackage 模拟考题 AnswertoQuestion2 2 Compilationandrunwiththeoutput Running 模拟考题 Question3 GivenareferencecalledttoaclasswhichextendsThread whichofthefollowingwillcauseittogiveupcyclestoallowanotherthreadtoexecute 1 t yield 2 yield 3 yield 100 orsomeothersuitableamountinmilliseconds4 yield t 模拟考题 AnswertoQuestion3 1 t yield 2 yield 本章小结 本章主要介绍了Java线程的编程技术 介绍了多线程的同步和互斥 以及应用举例
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!