




已阅读5页,还剩45页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第7章多线程 线程简介Thread类的子类创建线程实现Runnable接口基本的线程控制线程的调度多线程的互斥与同步Daemon线程 7 1线程简介 到目前为止所介绍过的各种范例都是单线程程序 也就是启动的Java程序在 同一时间 内只会做一件事 文本模式下最常进行的就是单线程程序 有时需要程序 同时 可以作很多事 即所谓多线程 Multi thread 程序 在窗口程序 网络程序中常使用多线程功能 了解多线程概念与注意事项是非常重要的 7 1 1进程与线程 程序是一段静态的代码 它是应用软件执行的蓝本 进程是程序的一次动态执行过程 它对应了从代码加载 执行至执行完毕的一个完整过程 这个过程也是进程本身从产生 发展至消亡的过程 线程是比进程更小的执行单位 一个进程在其执行过程中 可以产生多个线程 形成多条执行线索 每条线索 即每个线程也有它自身的产生 存在和消亡的过程 也是一个动态的概念 Java的多线程就是在操作系统每次分时给Java程序一个时间片的CPU时间内 在若干个独立的可控制的线程之间切换 7 1 2线程的状态 Java使用Thread类及其子类的对象来表示线程 线程在它的一个完整的生命周期中通常要经历如下的4种状态 1 创建状态 newThread 2 可运行状态 Runnable 3 不可运行状态 NotRunnable 4 死亡状态 Dead 7 2Thread类的子类创建线程 用Thread类或子类创建线程对象 编写Thread类的子类时 需要重写父类的run方法 其目的是规定线程的具体操作 否则线程就什么也不做 因为父类的run方法中没有任何操作语句 当JVM将CPU使用权切换给线程时 如果线程是Thread的子类创建的 该类中的run方法就立刻执行 7 3实现Runnable接口 创建线程的另一个途径就是用Thread类直接创建线程对象 使用Thread类创建线程对象时 常用的构造方法是 Thread Runnabletarget 该构造方法中的参数是一个Runnable类型的接口 因此 在创建线程对象时 必须向构造方法的参数传递一个实现Runnable接口类的实例 该实例对象称为所创线程的目标对象 例7 3 通过接口构造线程体 importjava awt Graphics importjava util Date publicclassep7 3extendsjava applet AppletimplementsRunnable 实现接口ThreadclockThread publicvoidstart if clockThread null clockThread newThread this Clock clockThread start 启动线程 publicvoidrun run 方法中是线程执行的内容while clockThread null repaint 刷新显示画面try clockThread sleep 1000 睡眠1秒 即每隔1秒执行一次 catch InterruptedExceptione publicvoidpaint Graphicsg Datenow newDate 获得当前的时间对象g drawString now getHours now getMinutes now getSeconds 5 10 显示当前时间 publicvoidstop clockThread stop clockThread null 本程序是Applet 要运行Applet程序 必须定义一个html文件 ep7 3 html文件内容如下 上面这个例子是通过每隔1秒种就执行线程的刷新画面功能 显示当前的时间 看起来的效果就是一个时钟 每隔1秒就变化一次 由于采用的是实现接口Runnable的方式 所以该类Clock还继承了Applet Clock就可以Applet的方式运行 构造线程体的两种方法的比较 1 使用Runnable接口1 可以将CPU 代码和数据分开 形成清晰的模型 2 还可以从其他类继承 3 保持程序风格的一致性 2 直接继承Thread类1 不能再从其他类继承 2 编写简单 可以直接操纵线程 无需使用Thread currentThread 7 4基本的线程控制 可以通过线程的方法进行基本的线程控制 下面我们熟悉一下常用的方法 1 start 方法线程调用该方法将启动线程 从新建状态进入就绪队列排队 一旦CPU资源轮转到它时 就脱离主线程开始自己的生命周期 2 run 方法系统的Thread类中 run 方法没有具体内容 用户需要在程序中重写run 方法来覆盖原来的run 方法 run 方法中定义线程对象被调度之后所执行的操作 是系统自动调用而用户不能引用的方法 当run 方法执行完毕 线程就变成死亡状态 在线程没有结束run 方法之前 不要让线程再调用start 方法 否则将发生IllegalThreadStateException异常 这一点在写程序的时候需要注意 3 sleep intmillsecond 方法sleep方法可以暂停一个线程的执行 在适当的时候再恢复其执行 就是让当前线程睡眠 停止执行 若干毫秒 线程由运行中状态进入不可运行状态 停止执行时间到后线程进入可运行状态 4 isAlive 方法测试线程状态 可以通过Thread中的isAlive 方法来获取线程是否处于活动状态 线程由start 方法启动后 直到其被终止之间的任何时刻 都处于Alive状态 线程处于新建状态时 调用isAlive 方法返回false 线程进入死亡状态后 调用isAlive 方法返回false 5 currentThread 方法currentThread 方法是Thread类的类方法 可以直接通过类名调用 该方法返回当前正在使用CPU资源的线程 6 Interrupt 方法interrupt 方法常用来 吵醒 休眠的线程 但线程调用sleep方法处于休眠状态时 一个占有CPU资源的线程可以让休眠的线程调用interrupt方法唤醒自己 导致休眠的线程发生InterruptedException异常 结束休眠 重新排队等待CPU资源 7 stop 方法通过调用线程的实例方法stop 来终止线程 线程终止后 其生命周期结束了 即进入死亡态 终止后的线程不能再被调度执行 8 join 方法一个线程在占有CPU资源期间 可以让其他线程调用join 方法和本线程联合 当前线程等待调用该方法的线程结束后 再重新排队等待CPU资源 以便恢复执行 如果当前线程准备联合的线程已经结束 也就是start方法体已经执行完 那么不会产生任何效果 TimerThreadtt newTimerThread 100 tt start publicvoidtimeout tt join 当前线程等待线程tt执行完后再继续往下执行 例7 5 线程联合的例子 publicclassep7 5 publicstaticvoidmain Stringargs ThreadJoina newThreadJoin a customer start a tvMaker start classThreadJoinimplementsRunnable TVtv Threadcustomer tvMaker ThreadJoin customer newThread this tvMaker newThread this customer setName 顾客 tvMaker setName 电视制造厂 publicvoidrun if Thread currentThread customer System out println customer getName 等 tvMaker getName 生产电视 try tvMaker join 线程customer开始等待tvMaker结束 catch InterruptedExceptione System out println customer getName 买了一台电视 tv name 价钱 tv price elseif Thread currentThread tvMaker System out println tvMaker getName 开始生产电视 请等 try tvMaker sleep 2000 catch InterruptedExceptione tv newTV 红星牌 3288 System out println tvMaker getName 生产完毕 classTV floatprice Stringname TV Stringname floatprice this name name this price price 7 5线程的调度 Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程 线程调度器按照线程的优先级决定应调度哪些线程来执行 线程的优先级用数字来表示 范围从1到10 即Thread MIN PRIORITY到Thread MAX PRIORITY 一个线程的缺省优先级是5 即Thread NORM PRIORITY 下述方法可以对优先级进行操作 intgetPriority 得到线程的优先级 voidsetPriority intnewPriority 当线程被创建后 可通过此方法改变线程的优先级 线程调度器按线程的优先级高低选择高优先级线程 进入运行中状态 执行 同时线程调度是抢先式调度 即如果在当前线程执行过程中 一个更高优先级的线程进入可运行状态 则这个线程立即被调度执行 抢先式调度又分为 时间片方式和独占方式 在时间片方式下 当前活动线程执行完当前时间片后 如果有其他处于就绪状态的相同优先级的线程 系统会将执行权交给其他就绪态的同优先级线程 当前活动线程转入等待执行队列 等待下一个时间片的调度 在独占方式下 当前活动线程一旦获得执行权 将一直执行下去 直到执行完毕或由于某种原因主动放弃CPU 或者是有一高优先级的线程处于就绪状态 下面几种情况下 当前线程会放弃CPU 1 线程调用了yield 或sleep 方法主动放弃 2 由于当前线程进行I O访问 外存读写 等待用户输入等操作 导致线程阻塞 或者是为等候一个条件变量 以及线程调用wait 方法 3 抢先式系统下 由高优先级的线程参与调度 时间片方式下 当前时间片用完 由同优先级的线程参与调度 7 6多线程的互斥与同步 经常有一些同时运行的线程需要共享数据 此时就需考虑其他线程的状态和行为 否则就不能保证程序的运行结果的正确性 7 6 1临界资源问题 下面是一个堆栈的类定义 classstack intidx 0 堆栈指针的初始值为0char data newchar 6 堆栈有6个字符的空间publicvoidpush charc 压栈操作data idx c 数据入栈idx 指针向上移动一位 publiccharpop 出栈操作idx 指针向下移动一位returndata idx 数据出栈 两个线程A和B在同时使用Stack的同一个实例对象 A正在往堆栈里push一个数据 B则要从堆栈中pop一个数据 如果由于线程A和B在对Stack对象的操作上的不完整性 会导致操作的失败 具体过程如下所示 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没有入栈 产生这种问题的原因在于对共享数据访问的操作的不完整性 7 6 2互斥锁 为解决操作的不完整性问题 在Java语言中 引入了对象互斥锁的概念 来保证共享数据操作的完整性 每个对象都对应于一个可称为 互斥锁 的标记 这个标记用来保证在任一时刻 只能有一个线程访问该对象 关键字synchronized来与对象的互斥锁联系 当某个对象用synchronized修饰时 表明该对象在任一时刻只能由一个线程访问 publicvoidpush charc synchronized this this表示Stack的当前对象data idx c idx publiccharpop synchronized this this表示Stack的当前对象idx returndata idx synchronized除了象上面讲的放在对象前面限制一段代码的执行外 还可以放在方法声明中 表示整个方法为同步方法 publicsynchronizedvoidpush charc 如果synchronized用在类声明中 则表明该类中的所有方法都是synchronized的 7 6 3多线程的同步 本小节将讨论如何控制互相交互的线程之间的运行进度 即多线程之间的同步问题 下面我们将通过多线程同步的模型 生产者 消费者问题来说明怎样实现多线程的同步 我们把系统中使用某类资源的线程称为消费者 产生或释放同类资源的线程称为生产者 在下面的Java的应用程序中 生产者线程向文件中写数据 消费者从文件中读数据 这样 在这个程序中同时运行的两个线程共享同一个文件资源 通过这个例子我们来了解怎样使它们同步 classSyncStack 同步堆栈类privateintindex 0 堆栈指针初始值为0privatechar buffer newchar 6 堆栈有6个字符的空间publicsynchronizedvoidpush charc 加上互斥锁while index buffer length 堆栈已满 不能压栈try this wait 等待 直到有数据出栈 catch InterruptedExceptione this notify 通知其它线程把数据出栈buffer index c 数据入栈index 指针向上移动 publicsynchronizedcharpop 加上互斥锁while index 0 堆栈无数据 不能出栈try this wait 等待其它线程把数据入栈 catch InterruptedExceptione this notify 通知其它线程入栈index 指针向下移动returnbuffer index 数据出栈 classProducerimplementsRunnable 生产者类SyncStacktheStack publicProducer SyncStacks theStack s publicvoidrun charc for inti 0 i 10 i c char Math random 26 A theStack push c 把字符入栈System out println Produced c 打印字符try Thread sleep int Math random 1000 catch InterruptedExceptione classConsumerimplementsRunnable 消费者类SyncStacktheStack publicConsumer SyncStacks theStack s publicvoidrun charc for inti 0 i 10 i c theStack pop 从堆栈中读取字符System out println Consumed c try Thread sleep int Math random 1000 catch InterruptedExceptione publicclassep7 7 publicstaticvoidmain Stringargs SyncStackstack newSyncStack 下面的消费者类对象和生产者类对象所操作的是同一个同步堆栈对象Runnablesource newProducer stack Runnablesink newConsumer stack Threadt1 newThread source 线程实例化Threadt2 newThread sink 线程实例化t1 start 线程启动t2 start 线程启动 类Producer是生产者模型 其中的run 方法中定义了生产者线程所做的操作 循环调用push 方法 将生产的10个字母送入堆栈中 每次执行完push操作后 调用sleep 方法睡眠一段随机时间 以给其他线程执行的机会 类Consumer是消费者模型 循环调用pop 方法 从堆栈中取出一个数据 一共取10次 每次执行完pop操作后 调用sleep 方法睡眠一段随机时间 以给其他线程执行的机会 在上述的例子中 通过运用wait 和notify 方法来实现线程的同步 在同步中还会用到notifyAll 方法 一般来说 每个共享对象的互斥锁存在两个队列 一个是锁等待队列 另一个是锁申请队列 锁申请队列中的第一个线程可以对该共享对象进行操作 而锁等待队列中的线程在某些情况下将移入到锁申请队列 比较一下wait notify 和notifyAll 方法 1 wait nofity notifyAll 必须在已经持有锁的情况下执行 所以它们只能出现在synchronized作用的范围内 也就是出现在用synchronized修饰的方法或类中 2 wait的作用 释放已持有的锁 进入等待队列 3 notify的作用 唤醒wait队列中的第一个线程并把它移入锁申请队列 4 notifyAll的作用 唤醒wait队列中的所有的线程并把它们移入锁申请队列 7 7Daemon线程 一个Daemon线程是在后台执行服务线程 例如网络服务器侦听连接端口的服务 隐藏系统线程 垃圾收集线程或其他JVM建立的线程 当程序中所有的非Daemon的线程都结束了 即使Daemon线程的run 方法中
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 国内旅游“一日游”合同(GF-2013-2405)在线签订流程图解
- 山东预制拼装房施工方案
- 情感咨询直播间运营方案
- 客厅半墙砖施工方案
- 新北区厂房消防施工方案
- 共有产权住房租赁合同(2023)附加协议书
- 零售餐饮服务业预付卡积分累积使用协议
- 历史与社会七下:第13课《可持续发展》教学设计
- 2025年青少年机器人技术等级考试理论综合试卷及答案
- 请假总结制定
- 2025年乡镇工会集体协商指导员岗位知识面试模拟题及答案
- 基于单片机技术的智能家居远程监控系统设计与实践
- 大学生心理健康教育(兰州大学)
- 粤教粤科版(2024)小学科学一年级上册《常见的天气》教案
- 医院感染管理的重要性
- 2025年中石油英语试题及答案
- 四渡赤水军事教学课件
- 刚新修订《治安管理处罚法》培训
- 建伍对讲机TH-K2-K4AT中文使用说明书
- 2025年浙江省能源集团招聘笔试备考题库(带答案详解)
- 部编一年级上册语文教学反思全集
评论
0/150
提交评论