JAVA 第八章
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
3.sleep(int millsecond) 优先级高的线程可以在它的run()方法 中调用sleep方法来使自己放弃处理器资 源,休眠一段时间。
4.isAlive() 在线程的run方法结束之前,即没有进入死亡状态之 前,线程调用isAlive()方法返回true,当线程进入死 亡状态后(实体内存被释放),线程仍可以调用方法 isAlive(),这时返回的值是false。(线程未调用 线程未调用 start方法之前 调用isAlive()方法返回false). 方法之前, isAlive()方法返回 start方法之前,调用isAlive()方法返回false). 需要注意的是,一个已经运行的线程在没有进入 死亡状态时,不要再给线程分配实体,由于线程只能 引用最后分配的实体,先前的实体就会成为“垃圾”, 并且不会被垃圾收集机收集掉。
当JVM将CUP使用权切换给线程时,如果线程是 Thread的子类创建的,该类中的run方法就立刻执行。 所以我们必须在子类中重写父类的run方法,Thread类 中的run()方法没有具体内容,程序要在Thread类的子 类中重写run()方法来覆盖父类的run()方法,run方法 规定了该线程的具体使命。 在线程没有结束run方法之前,不要让线程再调用 start方法,否则将发生 ILLegalThreadStateException异常。
8.1 Java中的线程 中的线程
程序是一段静态的代码,它是应用软件执行的蓝 本。进程是程序的一次动态执行过程,它对应了从代 码加载、执行至执行完毕的一个完整过程,这个过程 也是进程本身从产生、发展至消亡的过程。线程是比 进程更小的执行单位。一个进程在其执行过程中,可 以产生多个线程,形成多条执行线索,每条线索,即 每个线程也有它自身的产生、存在和消亡的过程,也 是一个动态的概念。
2.关于run方法中的局部变量 对于具有相同目标对象的线程,当其中一 个线程享用CPU资源时,目标对象自动调用接 口中的run方法,当轮到另一个线程享用CPU 资源时,目标对象会再次调用接口中的run方 法,。不同线程的run方法中的局部变量互不 干扰,一个线程改变了自己的run方法中局部 变量的值不会影响其他线程的run方法中的局 部变量。看例子6
下面的例子4中,两个线程:zhang和cheng,使用同 一目标对象。两个线程共享目标对象的money。当money 的值小于100时,线程zhang结束自己的run方法进入死亡 状态;当money的值小于60时,线程cheng结束自己的run 方法进入死亡状态。 例子5中共有4个线程:threadA、threadB、threadC 和threadD,其中threadA和threadB的目标对象a1, threadC和threadD的目标对象是a2。threadA和threadB 共享a1的成员number,而threadC和threadD共享a2的成 员number。
第八章 线程
本章导读 1. Java中的线程 2. 线程的生命周期 3. 线程的优先级与调度管理 4. Thread的子类创建线程 5.使用Runable接口 6.线程的常用方法 7.线程同步 8.在同步方法中使用wait()、notify 和notifyAll 9.线程的联合 10.守护线程
程序与进程
程序是为了完成某项任务编排的语句序列,程序是一 段静态的代码。 进程(Process)是具有一定独立功能的程序关于某个 数据集合上的一次运行活动,是系统进行资源分配和 调度的一个独立单位。程序只是一组指令的有序集合, 它本身没有任何运行的含义,只是一个静态实体。而 进程则不同,它是程序在某个数据集上的执行,是一 个动态实体。它因创建而产生,因调度而运行,因等 待资源或事件而被处于等待状态,因完成任务而被撤 消,反映了一个程序在一定的数据集上运行的全部动 态过程。
8.4 Thread 的子类创建线程
在Java语言中,用Thread类或子类创建线程对象。 这一节讲述怎样用Thread子类创建对象。 用户可以扩展 Thread类,但需要重写父类的run方 法,其目的是规定线程的具体操作,否则线程就什么 也不做,因为父类的run方法中没有任何操作语句。 下面例子3中除主线程外还有两个线程,这两个线程 分别在命令行窗口的左侧和右侧顺序地一行一行地输 出字符串。主线程负责判断输出的行数,当其中任何 一个线程输出8行后,就结束进程。本例题中用到了 System类中的类方法:exit(int n),主线程使用该方 法结束整个程序。
(c)线程使用CPU资源期间,执行了wait()方法,使得 当前线程进入等待状态。等待状态的线程不会主动 进到线程队列中排队等待CPU资源,必须由其他线程 调用notify()方法通知它,使得它重新进到线程队 列中排队等待CPU资源,以便从中断处继续运行。有 关wait、noftify和notifyAll方法将在第8节详细讨 论 (d) 线程使用CPU资源期间,执行某个操作进入阻塞 状态,比如执行读/写操作引起阻塞。进入阻塞状态 时线程不能进入排队队列,只有当引起阻塞的原因 消除时,线程才重新进到线程队列中排队等待CPU资 源,以便从原来中断处开始继续运行。
返回
8.5 使用 使用Runable接口 接口
使用Thread子类创建线程的优点是:我们可以在 子类中增加新的成员变量,使线程具有某种属性,也 可以在子类中新增加方法,使线程具有某种功能。但 是,Java不支持多继承,Thread类的子类不能再扩展 其他的类。
1.Runnable接口与目标对象 创建线程的另一个途径就是用Thread类直接创建线程对象。 使用Thread创建线程对象时,通常使用的构造方法是: Thread(Runnable target), 该构造方法中的参数是一个Runnable类型的接口,因此, 在创建线程对象时必须向构造方法的参数传递一个实现 Runnable接口类的实例,该实例对象称作所创线程的目标 该实例对象称作所创线程的目标 对象,当线程调用start方法后,一旦轮到它来享用CPU资 对象 源,目标对象就会自动调用接口中的run方法(接口回调), 这一过程是自动实现的,用户程序只需要让线程调用start 方法即可,也就是说,当线程被调度并转入运行状态时, 所执行的就是run()方法中所规定的操作。
上述程序在不同的计算机运行或在同一台计算机反复 运行的结果不尽相同,输出结果依赖当前CPU资源的使 用情况。为了使结果尽量不依赖于当前CPU资源的使用 情况,我们应当让线程主动调用sleep方法让出CPU的 使用权进入中断状态,如例子2所示:
返回
8.3 线程的优先级与调度管理
Java虚拟机(JVM)中的线程调度器负责管理线程,调度器 把线程的优先级分为10个级别,分别用Thread类中的类常量表示。 每个Java线程的优先级都在常数1: Thread.MIN PRIORITY 到常数10: Thread.MAX_PRIORITY 的范围内。如果没有明确地设置线程的优先级别,每个线程的 优先级都为常数5(包括主线程): Thread.NORM_PRIORITY, 线程的优先级可以通过setPriority(int grade)方法调整, 这一方法需要一个int类型参数。如果此参数不在1~10的范围内, 那么setPriority便产生一个lllegalArgumenException异常。 getPriority方法返回线程的优先级。需要注意是,有些操作系 统只能识别3个级别:1,5,10。 返回
在操作系统中引入线程带来的主要好处是: 1)在进程内创建、终止线程比创建、终止进程要快; (2)同一进程内的线程间切换比进程间的切换要快,尤其 是用户级线程间的切换。 另外,线程的出现还因为以下几个原因: (1)并发程序的并发执行,在多处理环境下更为有效。一 个并发程序可以建立一个进程,而这个并发程序中的若干并 发程序段就可以分别建立若干线程,使这些线程在不同的处 理机上执行。 2)每个进程具有独立的地址空间,而该进程内的所有线程 共享该地址空间。这样可以解决父子进程模型中,子进程 必须复制父进程地址空间的问题。 (3)线程对解决客户/服务器模型非常有效。
返回
wk.baidu.com
8.6 线程的常用方法
1.start() 线程调用该方法将启动线程,使之从新建 状态进入就绪队列排队,一旦轮到它来享用 CPU资源时,就可以脱离创建它的主线程独 立开始自己的生命周期了。 2.run() Thread类的run()方法与Runnable接口中 的run()方法的功能和作用相同,都用来定 义线程对象被调度之后所执行的操作,都是 系统自动调用而用户程序不得引用的方法。
返回
8.2 线程的生命周期
1.线程的4种状态 在Java语言中,Thread类及其子类创建的对象称作线 程,新建的线程在它的一个完整的生命周期中通常要 经历4种状态, (1)新建 (2)运行 线程创建后仅仅是占有了内存资源,在JVM管理的线 程中还没有这个线程,此线程必须调用start()方法 (从父类继承的方法)通知JVM,这样JVM就会知道又 有一个新一个线程排队等候切换了。
(4)死亡 处于死亡状态的线程不具有继续运行的能力。线程死 亡的原因有二,一个是正常运行的线程完成了它的全 部工作,即执行完run方法中的全部语句,结束了run 方法。另一个原因是线程被提前强制性地终止,即强 制run方法结束。所谓死亡状态就是线程释放了实体, 即释放分配给线程对象的内存。 现在,我们看一个完整的例子1,通过分析运行结果 阐述线程的4种状态。该例子中我们用Thread的子类: WriteWordThread创建了两个线程。
Java应用程序总是从主类的main方法开始执行。当 JVM加载代码,发现main方法之后,就会启动一个线程, 这个线程称作“主线程”,该线程负责执行main方法。 那么,在main方法中再创建的线程,就称为主线程中 的线程。如果main方法中没有创建其他的线程,那么 当main方法执行完最后一个语句,即main方法返回时, JVM就会结束我们的Java应用程序。如果main方法中又 创建了其他线程,那么JVM就要在主线程和其他线程之 间轮流切换,保证每个线程都有机会使用CPU资源, main方法即使执行完最后的语句,JVM也不会结束我们 的程序,JVM一直要等到主线程中的所有线程都结束之 后,才结束我们的Java应用程序。
进程与线程
线程和进程的关系是:线程是属于进程的,线 程运行在进程空间内,同一进程所产生的线程 共享同一内存空间,当进程退出时该进程所产 生的线程都会被强制退出并清除。线程可与属 于同一进程的其它线程共享进程所拥有的全部 资源,但是其本身基本上不拥有系统资源,只 拥有一点在运行中必不可少的信息(如程序计 数器、一组寄存器和栈)。
操作系统分类
1)单进程、单线程,MS-DOS大致是这种操 作系统; 2)多进程、单线程,多数UNIX(及类UNIX 的LINUX)是这种操作系统; 3)多进程、多线程,Win32(Windows NT/2000/XP等)、Solaris 2.x和OS/2都是这 种操作系统; 4)单进程、多线程,VxWorks是这种操作系 统
(3)中断 有4种原因的中断: (a) JVM将CPU资源从当前线程切换给其他线程,使本 线程让出CPU的使用权处于中断状态。 (b)线程使用CPU资源期间,执行了sleep(int millsecond)方法,使当前线程进入休眠状态。 sleep(int millsecond)方法是Thread类中的一个类 方法,线程一旦执行了sleep(int millsecond)方法, 就立刻让出CPU的使用权,使当前线程处于中断状态。 经过参数millsecond指定的豪秒数之后,该线程就 重新进到线程队列中排队等待CPU资源,以便从中断 处继续运行。