线程的状态与上下文切换

Java语言中,一个线程从其创建、启动到其运行结束的整个生命周期可能经历若干个状态,如下图所示。          

                      

Java线程的状态可以通过Thread实例的getState()方法获取。Thread.State所定义的线程状态包括以下几种。

       NEW:个刚创建而未启动的线程处于该状态。由于一个线程实例只能够被启动一次,因此一个线程只可能有一次处于该状态。

       RUNNABLE:该状态可以看成是一个符合的状态。它包括两个子状态:READY和RUNNING。前者表示处于该状态的线程可以被JVM的线程调度器(Scheduler)进行调度而使之处于RUNNING状态。后者表示处于该状态的线程正在运行,即,相应线程对象的run()方法中的代码所对应的指令正在由CPU执行。当Thread实例的yield()方法被调用时或者由于线程调度器的原因,相应线程的状态会由RUNNING转换为READY。

       BLOCKED:一个线程发起一个阻塞式I/O(Blocking I/O)操作后,或者试图去获得一个由其他线程持有的锁时,相应的线程会处于该状态。处于该状态的线程并不会占用CPU资源。当相应的I/O操作完成后,或者相应的锁被其他线程释放后,该线程的状态又可以转换为RUNNABLE。

      WAITING:一个线程执行了某些方法调用之后就会处于这种无限等待其他线程执行特定操作的状态。这些方法包括:Object.wait()、Thread.join()和LockSupport.park()。能够使相应线程从WAITING转换到RUNNABLE的相应方法包括:Object.notify()、Object.notifyAll()和LockSupport.unpark(thread)。

       TIMED_WAITING:改状态和WAITING类似差别在于处于该状态的线程并非无限等待其他线程执行特定操作,而是处于有时间限制的等待状态。当其他线程没有在指定的时间内执行该线程所期望的特定操作时,该线程的状态自动转换为RUNNABLE。

       TERMINATED:已经执行结束的线程处于该状态。由于一个线程实例只能够被启动一次,因此一个线程也只可能有一次处于该状态。Thread实例的run()方法正常返回或者由于抛出异常而提前终止都会导致相应线程处于该状态。

从上述的描述可知,一个线程在它的整个生命周期中,只可能一次处于NEW状态和TERMINATED状态。而一个线程的状态从RUNNABLE状态转换为BLOCKED、WAITING和TIMED_WAITING这几个状态中的任何一个状态都意味着上下文切换(Context Switch)。

上下文切换就好比我们接听手机电话的场景。比如,我们正在接听一个电话并与对方讨论某件事情的时候,这时候突然有另外一个来电。通常这个时候我们会跟对方说:“我先接个电话,你别挂断”,并在脑海中记录下和对方的讨论进行到什么程度了。然后,接听新的来电并且告诉对方稍后会回拨并将该来电挂断。接着,我们又会继续先前的讨论。如果在接听新来电之前,自己脑海中没有记录下当时的讨论进行到什么程度了,那么我们有可能会问对方“刚才我们讲到哪里了”这样的问题。

多线程环境中,当一个线程的状态由RUNNABLE转换为非RUNNABLE(BLOCKED、WAITING或者TIMED_WAITING)时相应线程的上下文信息需要被保存,以便于相应线程稍后再次进入RUNNABLE状态时能够在之前的执行进度的基础上继续执行,而一个线程的状态由非RUNNABLE状态转换进入RUNNABLE状态时可能涉及恢复之前保存的线程的上下文信息并在此基础上继续执行。这种对线程的上下文信息进行保存和恢复的过程就被称为上下文切换。

猜你喜欢

转载自blog.csdn.net/weixin_41209870/article/details/80951062