已阅读5页,还剩29页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java网络程序设计 信息工程系孙琳2013 08 第六章多线程 信息工程系孙琳2013 08 6多线程 6 1在Java中实现多线程6 2线程的五种状态6 3线程的优先级6 4线程的同步6 5线程的阻塞6 6守护线程6 7线程组 计算机基本知识补充 一般常见的Java应用程序都是单线程的 比如 用java命令运行一个最简单的HelloWorld的Java应用程序时 就启动了一个JVM进程 JVM找到程序程序的入口点main 然后运行main 方法 这样就产生了一个线程 这个线程称之为主线程 当main方法结束后 主线程运行完成 JVM进程也随即退出 对于一个进程中的多个线程来说 多个线程共享进程的内存块 当有新的线程产生的时候 操作系统不分配新的内存 而是让新线程共享原有的进程块的内存 因此 线程间的通信很容易 速度也很快 不同的进程因为处于不同的内存块 因此进程之间的通信相对困难 实际上 操作的系统的多进程实现了多任务并发执行 程序的多线程实现了进程的并发执行 多任务 多进程 多线程的前提都是要求操作系统提供多任务 多进程 多线程的支持 在Java程序中 JVM负责线程的调度 线程调度是值按照特定的机制为多个线程分配CPU的使用权 调度的模式有两种 分时调度和抢占式调度 分时调度是所有线程轮流获得CPU使用权 并平均分配每个线程占用CPU的时间 抢占式调度是根据线程的优先级别来获取CPU的使用权 JVM的线程调度模式采用了抢占式模式 计算机基本知识补充 所谓的 并发执行 同时 其实都不是真正意义上的 同时 众所周知 CPU都有个时钟频率 表示每秒中能执行cpu指令的次数 在每个时钟周期内 CPU实际上只能去执行一条 也有可能多条 指令 操作系统将进程线程进行管理 轮流 没有固定的顺序 分配每个进程很短的一段是时间 不一定是均分 然后在每个线程内部 程序代码自己处理该进程内部线程的时间分配 多个线程之间相互的切换去执行 这个切换时间也是非常短的 因此多任务 多进程 多线程都是操作系统给人的一种宏观感受 从微观角度看 程序的运行是异步执行的 用一句话做总结 虽然操作系统是多线程的 但CPU每一时刻只能做一件事 和人的大脑是一样的 计算机基本知识补充 什么是进程 进程就是一个在内存中独立运行的程序 有自己的地址空间 任务管理器里可以看到有多个进程 多任务 指操作系统能同时运行多个进程 程序 如xp系统可以同时运行写字板程序 画图程序 WORD EXCEL等 多线程 在同一程序中 有多个顺序流同时执行 图1JVM轮流执行线程 Java中的线程 Thread是process之中正在运行着的一段代码 通常是一个功能块 程序运行时可以派生出多个线程同时运行 每个线程 执行线索 也有它产生存在和消亡的过程 同类的多个线程共享一块内存空间和一组系统资源 另外 线程可以利用这些共享单元实现数据交换 通信和同步 线程与进程的比较 都是程序的多个顺序的流动态执行 线程是一种轻量级的进程 同类的多个线程是共享一块内存空间和一组系统资源 线程切换的开销小 每个进程都有独立的代码和数据空间 进程切换的开销大 一个进程中可以包含多个线程 返回 6 1在Java中实现多线程 Java的线程是通过java lang Thread类来实现的 每个线程都是通过某个特定Thread对象所对应的方法run 来完成其操作的 方法run 称为线程体 即线程的可执行代码 用Thread类创建线程 要将一段代码在一个新的线程上运行 该代码应该在一个类的run函数中 并且函数所在的类是Thread类的子类 子类要覆盖Thread类中的run函数 在子类的run函数中调用想在新线程上运行的程序代码 启动一个新的线程 我们不是直接调用Thread的子类对象的run函数 而是调用Thread子类对象的start 从Thread类继承到的 方法 Thread类对象的start方法将产生一个新的线程 并在该线程上运行该Thread类对象中的run方法 由于线程的代码段在run方法中 那么该方法执行完成后线程也就相应的结束了 因而我们可以通过控制run方法中循环的条件来控制线程的结束 多线程 文件 输入输出装置 各种系统资源 数据区段 程序区段 只有一个地方在执行 文件 输入输出装置 各种系统资源 程序区段 同时有数个地方在执行 传统的进程 多线程的任务 创建线程 有两种方法用来创建线程 继承Thread父类 并覆盖run 方法 classmythreadextendsThread publicvoidrun 覆盖该方法 声明一个实现Runnable接口的类 并实现run 方法 classmythreadimplementsRunnable publicvoidrun 实现该方法 用start 方法启动线程 Threadt1 newThread T1 start classMitiSayextendsThread publicMitiSay StringthreadName super threadName publicvoidrun System out println getName 线程运行开始 System out println getName 线程的优先级 getPriority for inti 0 i 10 i System out println i getName try sleep int Math random 10 catch InterruptedExceptione e printStackTrace System out println getName 线程运行结束 publicclassTestMitiThread publicstaticvoidmain String args System out println Thread currentThread getName 线程运行开始 newMitiSay A start newMitiSay B start newMitiSay C start System out println Thread currentThread getName 线程运行结束 publicclassMyThreadimplementsRunnable intcount 1 number publicMyThread intnum number num System out println 创建线程 number publicvoidrun while true System out println 线程 number 计数 count if count 6 return publicstaticvoidmain String args for inti 0 i 5 i newThread newMyThread i 1 start 6 2线程的五种状态 创建状态new当用new创建一个线程时 该线程尚未运行 start 尚未被调用可运行状态runnable一旦调用了start方法 该线程便是一个可运行的线程 CPU时间随时可能被分配给该线程 从而使得它执行 运行状态running运行run 方法代码阻塞状态block死亡状态dead 由于下面两个原因 线程将变成死线程 由于run方法的正常退出而自然死亡 没有捕获到的异常事件终止了run方法的执行 从而导致线程突然死 线程的状态 blocked 被中断运行 阻塞状态 线程不会被分配CPU时间 无法执行 可能阻塞于I O 或者阻塞于同步锁 blocked 被中断运行 当出现下列操作之一时 线程便进入中断状态 有人调用该线程的sleep 方法 该线程调用了wait 方法 该线程调用了一个在输入输出时中断的操作 也就是说 在输入和输出操作完成之前 该操作不会返回到它的调用程序 该线程试图锁定一个当前被另一个线程锁定了的对象 线程状态迁移图 新建 new 可运行 runnable 被中断 blocked 死亡 dead Run方法退出 异常停止 start 睡眠sleep 在I O上中断 I O操作完成 wait notify 等待锁定 锁可用 newthread 睡眠结束 6 3线程的优先级 线程的优先级代表该线程的重要程度 当有多个线程同时处于可执行状态并等待获得CPU时间时 线程调度系统根据各个线程的优先级来决定给谁分配CPU时间 优先级高的线程有更大的机会获得CPU时间 优先级低的线程也不是没有机会 只是机会要小一些罢了 线程的优先级仍然无法保障线程的执行次序 只不过 优先级高的线程获取CPU资源的概率较大 优先级低的并非没机会执行 在java中 每一个线程都有一个优先级 默认情况下 一个线程将继承其父线程的优先级 线程的优先级用数字来表示 范围从1到10 一个线程的缺省优先级是5Thread MIN PRIORITY 1Thread MAX PRIORITY 10Thread NORM PRIORITY 5调用Thread类的方法getPriority 和setPriority 来存取线程的优先级 setPriority 带有一个0 10之间的整数 如果大于10或者小于10 抛出IllegalArgumentException intgetPriority voidsetPriority intnewPriority t1 setPriority 10 t2 setPriority 1 不要误以为优先级越高就先执行 谁先执行还是取决于谁先取得CPU的资源 线程的问题 由于同一进程的多个线程共享同一片存储空间 在带来方便的同时 也带来访问冲突这个严重的问题 例如 当一个Java线程在修改一个共享变量时 另外一个线程正在使用或者更新同一个变量 这样容易导致程序出现错误的结果 解决办法 如果想解决这种问题 就需要使用同步 所谓同步就是在统一时间段中只有有一个线程运行 其他的线程必须等到这个线程结束之后才能继续执行 关键代码段 为解决操作的不完整性问题 在Java语言中 引入了对象互斥锁的概念 来保证共享数据操作的完整性 每个对象都对应于一个可称为 互斥锁 的标记 这个标记用来保证在任一时刻 只能有一个线程访问该对象 关键字synchronized来与对象的互斥锁联系 当某个对象用synchronized修饰时 表明该对象在任一时刻只能由一个线程访问 Synchronized obj 关键段obj锁对象 6 4线程的同步 synchronized方法publicsynchronized方法返回类型方法名 参数列表 其他代码 synchronized块synchronized 同步对象 需要同步的代码 一般都把当前对象this作为同步对象 java lang Thread类 这个类包含了创建和运行线程所需的一切东西构造函数 publicThread publicThread Runnabletarget publicThread ThreadGroupgroup Runnabletarget publicThread Stringname publicThread ThreadGroupgroup Stringname publicThread Runnabletarget Stringname publicThread ThreadGroupgroup Runnabletarget Stringname 参数说明 target 一个对象 线程启动后它的run方法会被调用 如果该参数为null 那么thread对象本身的run方法会被调用group 线程组对象name 新线程对象的名字 java lang Thread类 常用方法 publicvoidstart 启动该线程 将导致run方法被自动调用 该方法将立即返回 新线程将运行publicvoidrun 必须覆盖该方法 在方法体中添加你想要在该线程中执行的代码publicstaticvoidsleep longmillis throwsInterruptedException 使当前正在执行的线程睡眠指定的时间publicvoidinterrupt 用于将一个中断请求发送给线程publicstaticbooleaninterrupted 用于测试当前线程 即正在执行该指令的线程 是否已经被中断publicbooleanisInterrupted 用于测试某个线程是否已经被中断publicfinalbooleanisAlive 用于测试某个线程是否还活着publicfinalvoidsetPriority intnewPriority 设置线程的优先级 java lang Thread类 publicfinalvoidjoin longmillis throwsInterruptedException 使某个线程等待指定的时间 调用某线程的该方法 将当前线程与该线程 合并 即等待该线程结束 再恢复当前线程的运行 publicfinalintgetPriority 获得线程的优先级publicstaticThreadcurrentThread 返回代表当前正在执行的线程的Thread对象publicstaticvoidyield 使当前正在执行的线程临时暂停 以使其它的线程运行publicfinalvoidwait longtimeout throwsInterruptedException 当前线程被中断 并进入到一个对象的等待列表中 直到另外的线程调用同一个对象上的notify 或notifyAll 方法publicfinalvoidnotify 用于将对象等待列表中的任选的一个线程唤醒 使它再次成为可运行的线程publicfinalvoidnotifyAll 用于将对象等待列表中的所有线程唤醒 使它们再次成为可运行的线程 6 5线程的阻塞 1 sleep 方法 sleep 允许指定以毫秒为单位的一段时间作为参数 它使得线程在指定的时间内进入阻塞状态 不能得到CPU时间 指定的时间一过 线程重新进入可执行状态 典型地 sleep 被用在等待某个资源就绪的情形 测试发现条件不满足后 让线程阻塞一段时间后重新测试 直到条件满足为止 2 suspend 和resume 方法 两个方法配套使用 suspend 使得线程进入阻塞状态 并且不会自动恢复 必须其对应的resume 被调用 才能使得线程重新进入可执行状态 典型地 suspend 和resume 被用在等待另一个线程产生的结果的情形 测试发现结果还没有产生后 让线程阻塞 另一个线程产生了结果后 调用resume 使其恢复 3 yield 方法 yield 使得线程放弃当前分得的CPU时间 但是不使线程阻塞 即线程仍处于可执行状态 随时可能再次分得CPU时间 调用yield 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程 4 wait 和notify 方法 两个方法配套使用 wait 使得线程进入阻塞状态 它有两种形式 一种允许指定以毫秒为单位的一段时间作为参数 另一种没有参数 前者当对应的notify 被调用或者超出指定时间时线程重新进入可执行状态 后者则必须对应的notify 被调用 初看起来它们与suspend 和resume 方法对没有什么分别 但是事实上它们是截然不同的 区别的核心在于 前面叙述的所有方法 阻塞时都不会释放占用的锁 如果占用了的话 而这一对方法则相反 注意 第一 调用notify 方法导致解除阻塞的线程是从因调用该对象的wait 方法而阻塞的线程中随机选取的 我们无法预料哪一个线程将会被选择 所以编程时要特别小心 避免因这种不确定性而产生问题 第二 除了notify 还有一个方法notifyAll 也可起到类似作用 唯一的区别在于 调用notifyAll 方法将把因调用该对象的wait 方法而阻塞的所有线程一次性全部解除阻塞 当然 只有获得锁的那一个线程才能进入可执行状态 wait notify 与suspend resume 区别
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年福建莆田市第二十四中学春七年级地理收心摸底检测A练习卷
- 起诉物业违反合同
- 贵州导游证考试专项练习题含答案
- 酒店物业委托管合同
- 集体物业租赁合同
- 2026云南普洱博思欣医院有限公司招聘89人备考题库及答案详解(新)
- 2026内蒙古锡林郭勒盟阿巴嘎旗旗直事业单位引进急需紧缺人才2人备考题库及参考答案详解
- 2026广东广州中医药大学中药学院招聘校聘合同制人员1人备考题库及答案详解(典优)
- 2026年江西省住房和城乡建设厅直属事业单位高层次人才招聘1人备考题库附答案详解(突破训练)
- 2026江西司法警官职业学院高层次人才招聘8人备考题库(42)附答案详解(达标题)
- 北京东城区2024-2025学年七年级下学期期末数学试卷(解析版)
- 综合行政执法面试题及参考答案
- 健康体重 快乐成长
- 邮政行测考试试题及答案
- 七年级语文上册《古代诗歌四首》理解性默写与训练
- T/GXAS 830-2024经桡动脉穿刺介入诊疗患者术肢管理规范
- T/CECS 10298-2023二阶反应型水性环氧沥青防水粘结料
- 广铁校招机考题库及答案
- 人教版九年级语文中考真题汇编 《简·爱》(2022-2024)全国中考语文真题
- 光储充一体化智能充电站项目可行性研究报告建议书
- 生命教育与心理健康教育的融合路径研究
评论
0/150
提交评论