首页 理论教育 Java线程的生命周期及状态转换

Java线程的生命周期及状态转换

时间:2023-11-16 理论教育 版权反馈
【摘要】:当Thread对象创建完成时,线程的生命周期便开始了。通过一张图还不能完全描述清楚线程各状态之间的区别,接下来针对线程生命周期中的六种状态分别进行详细讲解。阻塞状态的线程只能先进入就绪状态,不能直接进入运行状态。

Java线程的生命周期及状态转换

在Java 中,任何对象都有生命周期,线程也不例外,它也有自己的生命周期。当Thread对象创建完成时,线程的生命周期便开始了。当run()方法中代码正常执行完毕或者线程抛出一个未捕获的异常(exception)或者错误(error)时,线程的生命周期便会结束。线程整个生命周期可以分为六个阶段,分别是新建状态(new)、就绪状态(runnable)、运行状态(running)、阻塞状态(blocked)、等待状态(waiting)和终止状态(terminated),线程的不同状态表明了线程当前正在进行的活动。在程序中,通过一些操作可以使线程在不同状态之间转换,如图11.5 所示。

图11.5 线程在不同状态之间转化的操作

图11.5 中展示了线程各种状态的转换关系,箭头表示可转换的方向,其中,单箭头表示状态只能单向转换,例如线程只能从新建状态转换到就绪状态,反之则不能;双箭头表示两种状态可以互相转换,例如就绪状态和运行状态可以互相转换。通过一张图还不能完全描述清楚线程各状态之间的区别,接下来针对线程生命周期中的六种状态分别进行详细讲解。具体如下:

1. 新建状态(new)

创建一个线程对象后,该线程对象就处于新建状态,此时它不能运行,和其他Java 对象一样,仅仅由Java 虚拟机为其分配了内存,没有表现出任何线程的动态特征。

2. 就绪状态(runnable)

新建状态的线程调用start()方法,就会进入可运行状态。在RUNNABLE 状态内部又可细分成两种状态:READY(就绪状态)和RUNNING(运行状态),并且线程可以在这两个状态之间相互转换。

RUNNABLE 内部状态转换:就绪状态:线程对象调用start()方法之后,等待JVM 的调度,此时线程并没有运行;运行状态:线程对象获得JVM 调度,如果存在多个CPU,那么允许多个线程并行运行。如果处于就绪状态的线程获得了CPU 的使用权,并开始执行run()方法中的线程执行体,则该线程处于运行状态。一个线程启动后,它可能不会一直处于运行状态,当运行状态的线程使用完系统分配的时间后,系统就会剥夺该线程占用的CPU 资源,让其他线程获得执行的机会。需要注意的是,只有处于就绪状态的线程才可能转换到运行状态。

3. 阻塞状态(Blocked)

运行状态的线程因为某些原因失去CPU 的执行权,会进入阻塞状态。阻塞状态的线程只能先进入就绪状态,不能直接进入运行状态。线程进入阻塞状态的两种情况:当线程A 运行过程中,试图获取同步锁时,却被线程B 获取;当线程运行过程中,发出IO 请求时。一个正在执行的线程在某些特殊情况下,如被人为挂起或执行耗时的输入/输出操作时,会让出CPU的使用权并暂时中止自己的执行,进入阻塞状态。线程进入阻塞状态后,就不能进入排队队列。只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。

下面就列举一下线程由运行状态转换成阻塞状态的原因,以及如何从阻塞状态转换成就绪状态。

(1)当线程试图获取某个对象的同步锁时,如果该锁被其他线程所持有,则当前线程会进入阻塞状态,如果想从阻塞状态进入就绪状态就必须得获取到其他线程所持有的锁。

(2)当线程调用了一个阻塞式的IO 方法时,该线程就会进入阻塞状态,如果想进入就绪状态就必须要等到这个阻塞的IO 方法返回。(www.xing528.com)

(3)当线程调用了某个对象的wait()方法时,也会使线程进入阻塞状态,如果想进入就绪状态就需要使用notify()方法唤醒该线程。

(4)当线程调用了Thread 的sleep(long millis)方法时,也会使线程进入阻塞状态,在这种情况下,只需等到线程睡眠的时间到了以后,线程就会自动进入就绪状态。

(5)当在一个线程中调用了另一个线程的join()方法时,会使当前线程进入阻塞状态,在这种情况下,需要等到新加入的线程运行结束后才会结束阻塞状态,进入就绪状态。

需要注意的是,线程从阻塞状态只能进入就绪状态,而不能直接进入运行状态,也就是说结束阻塞的线程需要重新进入可运行池中,等待系统的调度。

4. WAITING(等待状态)

运行状态的线程调用了无时间参数限制的方法后,如wait()、join()等方法,就会转换为等待状态。等待状态中的线程不能立即争夺CPU 使用权,必须等待其他线程执行特定的操作后,才有机会争夺CPU 使用权。

例如,调用wait()方法而处于等待状态中的线程,必须等待其他线程调用notify()或者notifyAll()方法唤醒当前等待中的线程;调用join()方法而处于等待状态中的线程,必须等待其他加入的线程终止。

5. TIMED_WAITING(定时等待状态)

运行状态中的线程调用了有时间参数限制的方法,如sleep(long millis)、wait(long timeout)、join(long millis)等方法,就会转换为定时等待状态。

定时等待状态中的线程不能立即争夺CPU 使用权,必须等待其他相关线程执行完特定的操作或者限时时间结束后,才有机会再次争夺CPU 使用权。

例如,调用了wait(long timeout) 方法而处于等待状态中的线程,需要通过其他线程调用notify()或者notifyAll()方法唤醒当前等待中的线程,或者等待限时时间结束后也可以进行状态转换。

6. 终止状态(Terminated)

当线程调用stop()方法或run()方法正常执行完毕后,或者线程抛出一个未捕获的异常(Exception)、错误(Error),线程就进入终止状态。一旦进入终止状态,线程将不再拥有运行的资格,也不能再转换到其他状态。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈