线程的操作
进程可以支持多个线程,它们看似同时执行,但互相之间并不同步。一个进程中的多个线程共享相同的内存地址空间,这就意味着它们可以访问相同的变量和对象,而且它们从同一堆中分配对象。尽管这让线程之间共享信息变得更容易,但您必须小心,确保它们不会妨碍同一进程里的其它线程。Java线程工具和API看似简单。但是,编写有效使用线程的复杂程序并不十分容易。因为有多个线程共存在相同的内存空间中并共享相同的变量,所以必须小心,确保您的线程不会互相干扰。
线程属性:为了正确有效地使用线程,必须理解线程的各个方面并了解Java 实时系统。必须知道如何提供线程体、线程的生命周期、实时系统如何调度线程、线程组、什么是幽灵线程(Demon Thread)。
线程体:所有的操作都发生在线程体中,在Java中线程体是从Thread类继承的run()方法,或实现Runnable接口的类中的run()方法。当线程产生并初始化后,实时系统调用它的run()方法。run()方法内的代码实现所产生线程的行为,它是线程的主要部分。
线程的状态:表示了线程在它的生命周期内的任何时刻所能处的状态以及引起状态改变的方法。这图并不是完整的有限状态图,但基本概括了线程中比较感兴趣和普遍的方面。以下讨论有关线程生命周期以此为据。
新线程态(New Thread):产生一个Thread对象就生成一个新线程。当线程处于"新线程"状态时,仅仅是一个空线程对象,它还没有分配到系统资源。因此只能启动或终止它。任何其他操作都会引发异常。例如,一个线程调用了new方法之后,并在调用start方法之前的处于新线程状态,可以调用start和stop方法。
可运行态(Runnable):start()方法产生运行线程所必须的资源,调度线程执行,并且调用线程的run()方法。在这时,线程的生命状态与周期:线程处于可运行态。该状态不称为运行态是因为这时的线程并不总是一直占用处理机。特别是对于只有一个处理机的PC而言,任何时刻只能有一个处于可运行态的线程占用处理机。Java通过调度来实现多线程对处理机的共享。注意,如果线程处于Runnable状态,它也有可能不在运行,这是因为还有优先级和调度问题。
阻塞/非运行态(Not Runnable):当以下事件发生时,线程进入非运行态。
- suspend()方法被调用;
- sleep()方法被调用;
- 线程使用wait()来等待条件变量;
- 线程处于I/O请求的等待。
死亡态(Dead):当run()方法返回,或别的线程调用stop()方法,线程进入死亡态。通常Applet使用它的stop()方法来终止它产生的所有线程。
线程的本操作:
- 派生:线程在进程内派生出来,它即可由进程派生,也可由线程派生。
- 阻塞(Block):如果一个线程在执行过程中需要等待某个事件发生,则被阻塞。
- 激活(unblock):如果阻塞线程的事件发生,则该线程被激活并进入就绪队列。
- 调度(schedule):选择一个就绪线程进入执行状态。
- 结束(Finish):如果一个线程执行结束,它的寄存器上下文以及堆栈内容等将被释放。
线程的另一个执行特性是同步。线程中所使用的同步控制机制与进程中所使用的同步控制机制相同。
线程优先级:虽然说线程是并发运行的。然而事实常常并非如此。正如前面谈到的,当系统中只有一个CPU时,以某种顺序在单CPU情况下执行多线程被称为调度(scheduling)。Java采用的是一种简单、固定的调度法,即固定优先级调度。这种算法是根据处于可运行态线程的相对优先级来实行调度。当线程产生时,它继承原线程的优先级。在需要时可对优先级进行修改。在任何时刻,如果有多条线程等待运行,系统选择优先级最高的可运行线程运行。只有当它停止、自动放弃、或由于某种原因成为非运行态低优先级的线程才能运行。如果两个线程具有相同的优先级,它们将被交替地运行。Java实时系统的线程调度算法还是强制性的,在任何时刻,如果一个比其他线程优先级都高的线程的状态变为可运行态,实时系统将选择该线程来运行。一个应用程序可以通过使用线程中的方法setPriority(int),来设置线程的优先级大小。
线程的组成:
- 一组代表处理器状态的CPU寄存器中的内容
- 两个栈,一个用于当线程在内核模式下执行的时候,另一个用于线程在用户模式下执行的时候。
- 一个被称为线程局部存储器(TLS,thread-local storage)的私有储存区域,各个子系统、运行库和DLL都会用到该储存区域。
- 一个被称为线程ID(thread ID,线程标识符)的唯一标识符(在内部也被称为客户ID——进程ID和线程ID是在同一个名字空间中生产的,所以它们永远不会重叠)。
- 有时候线程也有它们自己的安全环境,如果多线程服务器应用程序要模仿其客户的安全环境,则往往可以利用线程的安全环境。
幽灵线程:任何一个Java线程都能成为幽灵线程。它是作为运行于同一个进程内的对象和线程的服务提供者。例如,HotJava浏览器有一个称为"后台图片阅读器"的幽灵线程,它为需要图片的对象和线程从文件系统或网络读入图片。幽灵线程是应用中典型的独立线程。它为同一应用中的其他对象和线程提供服务。幽灵线程的run()方法一般都是无限循环,等待服务请求。
线程组:每个Java线程都是某个线程组的成员。线程组提供一种机制,使得多个线程集于一个对象内,能对它们实行整体操作。譬如,你能用一个方法调用来启动或挂起组内的所有线程。Java线程组由ThreadGroup类实现。当线程产生时,可以指定线程组或由实时系统将其放入某个缺省的线程组内。线程只能属于一个线程组,并且当线程产生后不能改变它所属的线程组。
多线程:对于多线程的好处这就不多说了。但是,它同样也带来了某些新的麻烦。只要在设计程序时特别小心留意,克服这些麻烦并不算太困难。在生成线程时必须将线程放在指定的线程组,也可以放在缺省的线程组中,缺省的就是生成该线程的线程所在的线程组。一旦一个线程加入了某个线程组,不能被移出这个组。
同步线程:许多线程在执行中必须考虑与其他线程之间共享数据或协调执行状态。这就需要同步机制。在Java中每个对象都有一把锁与之对应。但Java不提供单独的lock和unlock操作。它由高层的结构隐式实现,来保证操作的对应。然而,我们注意到Java虚拟机提供单独的monitorenter和monitorexit指令来实现lock和unlock操作。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请您通过400-62-96871或关注我们的公众号与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!







请先 登录后发表评论 ~