第13章Java多线程机制.ppt

上传人:本田雅阁 文档编号:2508922 上传时间:2019-04-04 格式:PPT 页数:25 大小:1.30MB
返回 下载 相关 举报
第13章Java多线程机制.ppt_第1页
第1页 / 共25页
第13章Java多线程机制.ppt_第2页
第2页 / 共25页
第13章Java多线程机制.ppt_第3页
第3页 / 共25页
亲,该文档总共25页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第13章Java多线程机制.ppt》由会员分享,可在线阅读,更多相关《第13章Java多线程机制.ppt(25页珍藏版)》请在三一文库上搜索。

1、第13章 Java多线程机制,13.1 进程与线程,13.1.1 操作系统与进程 程序是一段静态的代码,它是应用软件执行的蓝本。进程是程序的一次动态执行过程,它对应了从代码加载、执行至执行完毕的一个完整过程,这个过程也是进程本身从产生、发展至消亡的过程。现代操作系统和以往操作系统的一个很大的不同就是可以同时管理一个计算机系统中的多个进程,即可以让计算机系统中的多个进程轮流使用CPU资源,甚至可以让多个进程共享操作系统所管理的资源,13.1.2 进程与线程,线程不是进程,但其行为很像进程,线程是比进程更小的执行单位,一个进程在其执行过程中,可以产生多个线程,形成多条执行线索,每条线索,即每个线程

2、也有它自身的产生、存在和消亡的过程。和进程可以共享操作系统的资源类似,线程间也可以共享进程中的某些内存单元(包括代码与数据),并利用这些共享单元来实现数据交换、实时通信与必要的同步操作,但与进程不同的是,线程的中断与恢复可以更加节省系统的开销。具有多个线程的进程能更好地表达和解决现实世界的具体问题,多线程是计算机应用开发和程序设计的一项重要的实用技术,13.2 Java中的线程,13.2.1 Java的多线程机制 每个Java应用程序都有一个缺省的主线程。Java应用程序总是从主类的main方法开始执行。当JVM加载代码,发现main方法之后,就会启动一个线程,这个线程称作“主线程”,该线程负

3、责执行main方法。那么,在main方法的执行中再创建的线程,就称为程序中的其它线程。如果main方法中没有创建其他的线程,那么当main方法执行完最后一个语句,即main方法返回时,JVM就会结束我们的Java应用程序。如果main方法中又创建了其他线程,那么JVM就要在主线程和其他线程之间轮流切换,保证每个线程都有机会使用CPU资源,main方法即使执行完最后的语句(主线程结束),JVM也不会结束Java应用程序,JVM一直要等到Java应用程序中的所有线程都结束之后,才结束Java应用程序,操作系统让各个进程轮流执行,那么当轮到Java应用程序执行时,Java虚拟机就保证让Java应用程

4、序中的多个线程都有机会使用CPU资源,即让多个线程轮流执行。如果机器有多个CPU处理器,那么JVM就能充分利用这些CPU,获得真实的线程并发执行效果,13.2.2 线程的状态与生命周期,新建的线程在它的一个完整的生命周期中通常要经历如下的四种状态 1新建 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态。此时它已经有了相应的内存空间和其他资源 2运行 线程创建之后就具备了运行的条件,一旦轮到它来享用CPU资源时,即JVM将CPU使用权切换给该线程时,此线程的就可以脱离创建它的主线程独立开始自己的生命周期了,3中断 有4种原因的中断 JVM将CPU资源从当前线程切换给

5、其他线程,使本线程让出CPU的使用权处于中断状态。 线程使用CPU资源期间,执行了sleep(int millsecond)方法,使当前线程进入休眠状态 . 线程使用CPU资源期间,执行了wait()方法,使得当前线程进入等待状态。 线程使用CPU资源期间,执行某个操作进入阻塞状态,比如执行读/写操作引起阻塞。,4死亡 处于死亡状态的线程不具有继续运行的能力。线程死亡的原因有二,一个是正常运行的线程完成了它的全部工作,即执行完run()方法中的全部语句,结束了run()方法。另一个原因是线程被提前强制性地终止,即强制run()方法结束。所谓死亡状态就是线程释放了实体,即释放分配给线程对象的内存

6、。,13.2.3 线程调度与优先级,Java虚拟机(JVM)中的线程调度器负责管理线程,调度器把线程的优先级分为10个级别,分别用Thread类中的类常量表示。每个Java线程的优先级都在常数1和10之间,即 Thread.MIN_PRIORITY和Thread.MAX_PRIORITY之间。如果没有明确地设置线程的优先级别,每个线程的优先级都为常数5,即Thread.NORM_PRIORITY 线程的优先级可以通过setPriority(int grade)方法调整,这一方法需要一个int类型参数。如果此参数不在110的范围内,那么setPriority便产生一个lllegalArgumen

7、Exception异常。getPriority方法返回线程的优先级,13.3 Thread的子类创建线程,在Java语言中,用Thread类或子类创建线程对象。这一节讲述怎样用Thread子类创建线程对象。在编写Thread类的子类时,需要重写父类的run()方法,其目的是规定线程的具体操作,否则线程就什么也不做,因为父类的run()方法中没有任何操作语句,13.4 使用Runnable接口,使用Thread子类创建线程的优点是:可以在子类中增加新的成员变量,使线程具有某种属性,也可以在子类中新增加方法,使线程具有某种功能。但是,Java不支持多继承,Thread类的子类不能再扩展其他的类,1

8、3.4.1 Runnable接口与目标对象,创建线程的另一个途径就是用Thread类直接创建线程对象。使用Thread创建线程通常使用的构造方法是: Thread(Runnable target) 该构造方法中的参数是一个Runnable类型的接口,我们知道线程间可以共享相同的内存单元(包括代码与数据),并利用这些共享单元来实现数据交换、实时通信与必要的同步操作。对于Thread(Runnable target)构造方法创建的线程,轮到它来享用CPU资源时,目标对象就会自动调用接口中的run()方法,因此,对于使用同一目标对象的线程,目标对象的成员变量自然就是这些线程共享的数据单元。另外,创建

9、目标对象类在必要时还可以是某个特定类的子类,因此,使用Runnable接口比使用Thread的子类更具有灵活性,13.4.2 关于run方法启动的次数,在上述例13-3中“红蚂蚁”和“黑蚂蚁”是具有相同目标对象的两个线程,当其中一个线程享用CPU资源时,目标对象自动调用接口中的run方法,当轮到另一个线程享用CPU资源时,目标对象会再次调用接口中的run方法,也就是说run()方法已经启动运行了两次,分别运行在不同的线程中,即运行在不同的时间片内,13.4.3 在线程中启动其它线程,线程通过调用start()方法将启动该线程,使之从新建状态进入就绪队列排队,一旦轮到它来享用CPU资源时,就可以

10、脱离创建它的主线程独立开始自己的生命周期了。在前面的例子中,都是在主线程中启动的其它线程,实际上也可以再任何一个线程中启动另外一个线程,13.5 线程的常用方法,1start() 线程调用该方法将启动线程,使之从新建状态进入就绪队列排队,一旦轮到它来享用CPU资源时,就可以脱离创建它的线程独立开始自己的生命周期了。需要特别注意的是,线程调用start()方法之后,就不必再让线程调用start()方法,否则将导致IllegalThreadStateException异常,即只有处于新建状态的线程才可以调用start()方法,调用之后就进入排队等待CUP状态了,如果再让线程调用start()方法显

11、然是多余的,2run() Thread类的run()方法与Runnable接口中的run()方法的功能和作用相同,都用来定义线程对象被调度之后所执行的操作,都是系统自动调用而用户程序不得引用的方法。系统的Thread类中,run()方法没有具体内容,所以用户程序需要创建自己的Thread类的子类,并重写run()方法来覆盖原来的run()方法。当run方法执行完毕,线程就变成死亡状态,所谓死亡状态就是线程释放了实体,即释放分配给线程对象的内存。在线程没有结束run()方法之前,不赞成让线程再调用start()方法,否则将发生ILLegalThreadStateException异常,3slee

12、p(int millsecond) 线程的调度执行是按照其优先级的高低顺序进行的,当高级别的线程未死亡时,低级线程没有机会获得CPU资源。有时,优先级高的线程需要优先级低的线程做一些工作来配合它,或者优先级高的线程需要完成一些费时的操作,此时优先级高的线程应该让出CPU资源,使优先级低的线程有机会执行。为达到这个目的,优先级高的线程可以在它的run()方法中调用sleep方法来使自己放弃CPU资源,休眠一段时间。休眠时间的长短由sleep方法的参数决定,millsecond是毫秒为单位的休眠时间。如果线程在休眠时被打断,JVM就抛出InterruptedException异常。因此,必须在tr

13、ycatch语句块中调用sleep方法,4isAlive() 线程处于“新建”状态时,线程调用isAlive()方法返回false。当一个线程调用start()方法,并占有CUP资源后,该线程的run()方法就开始运行,在线程的run()方法结束之前,即没有进入死亡状态之前,线程调用isAlive()方法返回true。当线程进入“死亡”状态后(实体内存被释放),线程仍可以调用方法isAlive(),这时返回的值是false,5currentThread() currentThread()方法是Thread类中的类方法,可以用类名调用,该方法返回当前正在使用CPU资源的线程。,6interrup

14、t() intertupt方法经常用来“吵醒”休眠的线程。当一些线程调用sleep方法处于休眠状态时,一个占有CPU资源的线程可以让休眠的线程调用interrupt()方法“吵醒”自己,即导致休眠的线程发生InterruptedException异常,从而结束休眠,重新排队等待CPU资源,13.6 线程同步,13.6.1 什么是线程同步 所谓线程同步就是若干个线程都需要使用一个synchronized修饰的方法,即程序中的若干个线程都需要使用一个方法,而这个方法用synchronized给予了修饰。多个线程调用synchronized方法必须遵守同步机制:当一个线程使用这个方法时,其他线程想使

15、用这个方法时就必须等待,直到线程A使用完该方法。在使用多线程解决许多实际问题时,可能要把某些修改数据的方法用关键字:synchronized来修饰,13.6.2 通过同步避免切换的影响,当一个进程中有多个线程时,JVM让每个线程都有机会获得CPU的使用权,以便使用CPU资源执行线程中的操作,即JVM轮流让各个线程使用CPU,这样一来就会出现程序的运行结果可能依赖JVM切换线程使用CPU的时机,而JVM在线程之间切换使用CPU的时机是根据当前CPU的具体情况而定的。因此,当一个线程使用CUP资源的时,即使线程没有完成自己的全部操作JVM也可能会中断当前线程的执行,把CPU的使用权切换给下一个排队

16、等待的线程,当前线程将等待CPU资源的下一次轮回,然后从中断处继续执行,13.7 在同步方法中使用wait()、notify 和notifyAll()方法,当一个线程使用的同步方法中用到某个变量,而此变量又需要其它线程修改后才能符合本线程的需要,那么可以在同步方法中使用wait()方法。wait方法可以中断方法的执行,使本线程等待,暂时让出CPU的使用权,并允许其它线程使用这个同步方法。其它线程如果在使用这个同步方法时不需要等待,那么它使用完这个同步方法的同时,应当用notifyAll()方法通知所有的由于使用这个同步方法而处于等待的线程结束等待。曾中断的线程就会从刚才的中断处继续执行这个同步

17、方法,并遵循“先中断先继续”的原则。如果使用notify()方法,那么只是通知处于等待中的线程的某一个结束等待。 wait()、notify()和notifyAll()都是Object类中的final方法,被所有的类继承、且不允许重写的方法,13.8 线程联合,一个线程A在占有CPU资源期间,可以让其它线程调用join()和本线程联合, 如: B.join(); 我们称A在运行期间联合了B。如果线程A在占有CPU资源期间一旦联合B线程,那么A线程将立刻中断执行,一直等到它联合的线程B执行完毕,A线程再重新排队等待CPU资源,以便恢复执行。如果A准备联合的B线程已经结束,那么B.join()不会产生任何效果,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1