




已阅读5页,还剩30页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java程序设计,第13章 多线程开发,学习目标,理解多线程概念和运行机制 能够区别Thread和Runnable两种方法创建线程的差异 掌握线程的并发访问处理机制,避免冲突和死锁 理解线程的生命周期,掌握线程状态变换的条件,基本概念 程序和进程 进程和线程 Java中的线程技术,13.1创建线程,继承了父类Thread,表明了它是一个线程类 构造方法中的String类型的参数是作为线程的名字 每个线程类都需要覆盖从父类Thread继承的run方法,public class Clerk extends Thread public Clerk(String name) super(name); Override public void run() super.run(); / 添加具体的工作代码 ,构造函数 Thread() Thread(Runnable target) Thread(Runnable target, String name) Thread(String name),13.1.2实现Runnable接口创建线程目标类,Thread类同样实现了Runnable接口。 如果在run()方法运行时,需要获得当前执行线程的信息,可以使用Thread的类方法currentThread()获得。,public class Clerk implements Runnable Override public void run() / 添加具体的工作代码 ,Thread clerk=new Thread(new Clerk();,13.1.3 定义线程执行的任务,定制线程的任务体 要想使得创建的线程对象能够按照要求工作,还必须为它分派任务。就是重写线程类中的run()方法。 需要注意的是,这里定义的run()方法只是一个线程实例运行时会自动执行的任务代码,由虚拟机环境来寻找并执行run()方法中的任务代码,应用程序不要直接执行该方法。,public class Clerk implements Runnable Override public void run() while(true) 从排队机上获取一份新的业务 if 没有业务 休息,直到得到业务办理通知 else 判断业务类型,进行处理 处理完一笔,允许休息一定时间 ,13.1.4创建线程实例,执行任务,基于Runnable接口的实现类创建线程实例,基于Thread及其子类创建实例,Clerk clerk=new Clerk();,Thread clerk=new Thread(new Clerk();,启动线程,clerk.start();,13.2失控的线程,如果一个程序运行中创建的多个线程互不影响,那么多线程的编程也许是一件很简单的事情,但现实往往比预想的复杂,多线程的编程困难之处在于线程间共享资源出现的协同工作问题。,13.3线程间的同步和互斥,互斥对象的访问 当多个线程同时对同一个对象状态进行更新时,就可能会导致更新异常。为了避免这种异常,Java语言提供了synchronized关键字用于对象更新的保护。 synchronized包含的代码块看做是“临界区”。在Java语言中,要想进入这个临界区,首先要获得受保护对象(如tran.getAccount()对象)的监视器(monitor)。 另外,当线程不能获得该对象的锁时,线程将会被阻塞,暂时停止运行,一直到它获得锁,然后继续运行程序。,13.3.2互斥方法的访问,对同一个对象的方法互斥访问,/* 程序13-1 QueueMachine:增加了方法保护机制的排队机 */ import java.util.LinkedList; public class QueueMachine private LinkedList queue = new LinkedList(); private boolean isEmpty() return queue.isEmpty(); public synchronized Transaction get() Transaction tran = queue.poll(); return tran; public synchronized void add(Transaction tran) this.queue.add(tran); ,synchronized的作用 任何时候只能有一个线程访问一个对象里受此修饰符保护的方法。 当一个对象有多个synchronized修饰的方法时,任何时候只能有一个这样的受保护方法被一个线程所执行。 不同线程执行同一类型的不同对象中的受保护方法时,彼此互不影响。 附加上synchronized修饰符的方法,同一对象在一个时刻只能被一个线程所访问,可能会造成排队执行的现象,影响程序执行的性能。,13.3.3线程间的同步,同步问题 什么是同步? 利用wait()/notify()/notifyAll()解决线程同步问题,13.3.3线程间的同步,wait()方法 当对象执行该方法时,正在访问此对象的线程将被阻塞,暂时停止运行,直到其它线程执行这个对象的notify()或notifyAll()方法,唤醒它为止。唤醒后的线程应该继续对导致该线程被提醒的条件进行测试,如果不满足该条件,则继续等待。,/访问互斥对象 synchronized (obj) while () obj.wait(); . /条件满足时的代码 ,/访问互斥方法 synchronized type method() while () this.wait(); . /条件满足时的代码 ,/银行职员线程调用get方法,从排队机获得一项业务 public synchronized Transaction get() hrows InterruptedException while(queue.isEmpty() this.wait(); Transaction tran = queue.poll(); return tran; ,notify()方法 唤醒在此对象监视器上等待的单个线程。如果多个线程都在此对象上等待,则会选择唤醒其中一个线程,选择是任意性的。直到当前线程放弃此对象上的锁定,被唤醒的线程才能继续执行。 notifyAll()方法 唤醒在此对象监视器上等待的所有线程,这些线程经会重新请求此对象的监视器,获得后继续执行。同notify()一样,直到当前线程放弃此对象上的锁定,被唤醒的线程才能继续执行。,/业务发生器线程调用add方法,向排队机增加一项待处理业务 public synchronized void add(Transaction tran) this.queue.add(tran); this.notifyAll(); ,注意,实践中使用wait-notify机制时需要注意以下几个问题。 wait()、notify()和notifyAll()方法均应置入临界区内的代码中,也就是说,当一个线程碰到此类方法时,但并没有获得该方法所在对象的监视器时,一个IllegalMonitorStateException异常将会被抛出。 wait()方法总是处在一个循环语句内,循环的作用在于检测是否拥有足够的资源一边继续运行线程,如果条件不满足,则线程将被置于该方法所属对象的监视器等待队列中。,13.3.4线程的死锁问题,在多线程访问时,除了上述的线程冲突外,另外一种需要避免的就是著名的死锁了,如下面的代码就反映了典型的死锁关系。,13.4线程的状态与转换,新建就绪,Clerk clerk1 = new Clerk(queue, “职员甲“);,新建状态,clerk1.start();,就绪状态,就绪-运行 应用程序不能控制线程从就绪转为运行状态,这种状态的变化是由系统调度实现的。当解释器调度执行线程实例的run()方法后,线程就开始运行,状态从就绪状态转化为运行状态。 当线程运行时,会一直运行到结束,除非遇到阻塞条件或者分配的时间片用完,或者被暂停。因此,应当精心的组织线程的运行任务代码,使得它不至于长时间的占据处理机资源而导致其它线程无法工作,特别是在单处理机环境下,运行就绪,public static void yield(),调用Thread类的类方法yield(),此方法暂停当前正在执行的线程对象,并执行其他线程。 调用此方法时如果没有其它线程正在等待的话,线程实例将会立即获得重新执行的机会。 在分时系统中,当线程分配到的处理机运行时间片,或在抢占式调度策略下,高优先级的线程到来,将抢占低优先级线程获得的处理机而优先运行,这些都会导致线程从运行状态转为就绪状态。,4 运行结束 在运行过程中,如果一切正常,通常会很快运行结束,因为一个线程的任务执行过程通常是一些比较关键的代码,不应耗费很长时间,否则就不足以应付高负载的业务请求。 在run()方法中的代码执行结束,线程就进入结束状态。 另外一种方法,通过调用线程对象的interrupt()方法,一个线程向另外一个线程发送消息告诉该线程应该停止运行。,public void interrupt(),5 运行阻塞 线程的运行并不总是一帆风顺。在运行的过程中,线程可能会遇到得不到足够的资源的情况,这些问题都会造成线程的阻塞 还有一种情况,两个或多个线程间需要协同,才能保证程序运行的正确性。例如,一个线程运行需要另外一个线程提供资源,在资源不足的情况下,线程就需要停下来等待。,(1)线程休眠,public static void sleep(long millis) throws InterruptedException,在线程的run()方法代码中的合适位置放置一条Thread.sleep()语句,执行该语句,将使线程状态置为阻塞(休眠)状态,直至苏醒。 该方法的参数即指定线程休眠的毫秒。如果线程休眠时间已到,线程就会被重新激活,并被置为就绪状态,等待获得处理机。 如果在休眠时,检测到了该线程的中断信号,将抛出InterruptedException异常,并清除该中断信号。 需要注意的是,只能在当前线程中执行sleep()方法,不能指定一个线程sleep,因为无法得知一个线程的准确状态,只有当前的线程正在运行,才可以使它休眠。 该方法的执行不会使当前线程丢失任何监视器的所属权。,(2)等待 当线程实例执行任务代码时,向另一对象obj发出消息,执行某一方法的过程中,如果obj执行wait()方法,则使得该线程实例被阻塞,成为该obj对象的等待线程队列中的一个。,3)连接线程 如果一个线程需要等待另外一个线程的消亡才可以继续执行,这是就可以用调用对方线程实例的join()方法。,public final void join() throws InterruptedException public final void join(long millis) throws InterruptedException,generator.join();/ 当前线程等待线程generator执行完后再继续往下执行。 generator.join(1000);/ 当前线程等待线程generator1000毫秒。,如果两个工作需要同步,其中一个工作需要等待另一项工作的结果,则代码可以类似下面程序:,B b = new B(); /创建线程实例b b.start();/做工作B A();/做工作A b.join();/当前线程等待线程B执行完成。 C();/继续工作C。,6 阻塞就绪 被阻塞的主要原因有sleep()、wait()和join()。 由于休眠造成的阻塞在休眠时间结束,阻塞就会被解除转入到就绪状态等待被调度执行。 由于碰到了wait()而引起的阻塞,则需要相应的notify()或者notifyAll()来唤醒才可以。 由于join()造成的阻塞,则相应线程执行完毕或时间结束,即可进入就绪状态。,13.5线程的管理,1.线程的优先级 线程的优先级用数字来表示,范围从1到10,即Thread.MIN_PRIORITY到Thread.MAX_PRIORITY。 一个线程的缺省优先级是5,即Thread.NORM_PRIORITY。 Java运行系统总是选择当前优先级最高的处于就绪状态的线程来执行。如果几个就绪线程由相同的优先级,将会用时间片方法轮流分配处理机。 当线程被创建后,可通过下述方法改变线程的优先级 int getPriority(); /得到线程的优先级 void setPriority(int newPriority);,13.5.2线程的中断,利用线程对象的interrupt()方法来向该线程发出一个中断信号。,public void interrupt(),通过发送中断消息的方式本身并不会停止线程的执行,只是在线程中设置了一个中断标记,表明了一个中断请求,这个标记如果生效,必须在run()方法中被检测 当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时将会抛出异常InterruptedException,使用interrupted()方法检测线程的状态 Thread提供了一个类方法interrupted()来检测当前线程是否已经中断。,public static boolean interrupted(),interrupted()方法会检查当前线程的中断状态,如果为“被中断状态”则改变当前线程为“非中断状态”并返回true,如果为“非中断状态”则返回false。,利用isInterrupted ()检查线程的状态 Thread提供了一个实例方法isInterrupted ()来检测当前线程是否已经中断。,public boolean isInterrupted (),isInterrupted ()方法是一个线程对象的测试方法,用来从线程外部验证该线程是否被中断了,并且不会改变它的状态。,try Thread.sleep(rand.nextInt(200 + rand.nextInt(3); catch (InterruptedException e) if (queue.isEmpty() working = “closed“; ,13.5.3守护线程和用户线程,守护线程或用户线程。 public final void setDaemon(boolean on) 利用setDaemon(true)方法可以将该线程标记为守护线程,反之则是用户线程。 守护线程只是一个在后台运行的线程,从属于生成它的线程,一旦生成它的线程结束时,此守护线程也会一并结束。当正在运行的线程都是守护线程时,Java 虚拟机退出。 一个线程如果是由守护线程创建的,也默认是守护线程。 该方法必须在启动线程前调用,即在start()执行之前。 用户线程的运行独立于生成它的线程,也就是即使生成它的线程已经结束运行,用户线程还可以继续运行,直到结束,如何使用 例如,一个服务器进程可以创建若干个守护
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 三年级拨河作文500字左右
- 2025-2030中国防守曲棍球头行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国镀锌镍行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国铝合金建材行业发展分析及发展趋势预测报告
- 2025-2030中国钢压延行业市场发展分析及竞争格局与投资前景研究报告
- 2025-2030中国针棉织品市场调研及发展策略研究报告
- 2025-2030中国金属陶瓷行业市场深度调研及发展趋势与投资前景预测研究报告
- 2025-2030中国重组制药厂的小瓶适配器行业市场现状供需分析及投资评估规划分析研究报告
- 2025年特定蛋白分析仪器试剂项目合作计划书
- 2025-2030中国邮箱通知行业市场发展趋势与前景展望战略研究报告
- 750千伏变电站工程项目管理实施规划
- 《中医内科学》教学课件-痿证(49页PPT)
- 深圳初中化学知识点总结(大全)
- 数据中心机房项目可行性研究报告-用于立项备案
- 热风炉耐材砌筑施工方案
- (完整版)高中状语从句练习题带答案
- 人教版六年级道德与法治下册课件 第二单元 爱护地球 共同责任 4 地球——我们的家园
- (完整word版)宿舍建筑平面图
- 《理工英语1》课程导学PPT课件
- 电梯台账表格(精编版)
- 禁止吸烟管理制度
评论
0/150
提交评论