[读书笔记][CoreJava2AdvancedFeatures][多线程]1.3线程状态

来源:互联网 发布:千图网软件下载 编辑:程序博客网 时间:2024/06/05 07:47

1.3线程状态

线程可以有以下4个状态:
  • New —— 新生
  • Runnable —— 可运行
  • Block —— 被阻塞
  • Dead —— 死亡
     
下面一节会对每一个状态作出解释。

1.3.1 新生线程

当你用new操作符创建一个线程时,例如用new Thread(r),线程还没有开始运行。此时线程处在New——新生状态。当一个线程处在新生状态时,程序还没有开始运行线程中的代码。在线程可以运行之前,还有一些簿记工作要做。

1.3.2 可运行线程

一旦调用了start方法,该线程就成为可运行——Runnable的了。一个可运行线程可能实际上正在运行,也可能没有,这取决于操作系统为该线程提供的运行时间。(不过,Java规范并没有把这种情况作为一种单独的状态,一个正在运行的线仍然处于可运行状态。)
注意:可运行状态和Runnable接口没有任何关系。
一旦开始运行,它不需要始终保持运行。事实上,线程在运行过程中有时需要被中断,目的是使其他线程获得运行的机会。线程调度的细节取决于操作系统所提供的服务。使用抢占式调度的系统给每个可运行的线程一个时间片来处理任务。当这个时间片用完时,操作系统剥夺该线程对资源的占用,使其他的线程有机会运行。在选择下一个线程时,操作系统会考虑到线程的优先级。

所有现代的桌面和服务器系统都使用抢占式调度。但一些小型设备,例如手机,可能会采用协作式调度。这样的设备中,一个线程只有在调用sleep或yield这样的方法时才会丢失控制权。

在一个多处理器的机器上,每个处理器都可以运行一个线程,你可以使多个线程并行运行。当然,如果线程个数大于处理器个数,那么调度器将仍旧采用时间片机制。

记住,在任何给定的时刻,一个可运行线程可能在运行,也可能不是。(这正是为什么把这个状态称为“runnable”而不是“running”。)

1.3.3 被阻塞线程
当发生以下任何在一种情况时,线程就进入被阻塞状态:
  • 线程通过调用sleep方法进入睡眠状态;
  • 线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
  • 线程试图得到一个锁,而该锁正被其他线程持有。
  • 线程在等待某个触发条件;
  • 有人调用了线程的suspend方法。不过这个方法已经过时了,而你不应该在你的代码中调用它。
     
下图显示了线程的各种状态及状态之间的转化关系。

当一个线程被阻塞(或者,当他死亡时),另一个线程就可以被调度运行了。当一个被阻塞的线程重新被激活时(例如,由于它的睡眠时间已经到达了指定的毫秒数或因为它所等待的I/O已经完成),调度器检查他的优先级是否高于当前的运行线程,如果是,它就将抢占当前线程的资源并开始运行。
通过以下几种途径中的一种,线程可以从被阻塞状态回到可运行状态。
  1. 线程被置于睡眠状态,且已经经过指定的毫秒数;
  2. 线程正在等待I/O操作完成,且该操作已经完成;
  3. 线程正在等待另一个线程所持有的锁,且另一个线程已经释放该锁的所有权;(也有可能等待超时,当超时发生时,线程解除阻塞。)
  4. 线程正在等待某个触发条件,且另一个线程发出了信号表明已经发生了变化。(如果为线程的等待设置了一个超时,那么当超时发生时线程将解除阻塞。)
  5. 线程已被挂起,且有人调用了它的resume方法。不过,由于suspend方法已经过时,resume方法也就随之被弃用了,你不应该在自己的代码中调用它。
       
一个被阻塞线程只能通过和先前阻塞它的相同过程重新进入可运行状态。要特别注意,你不能通过调用resume方法来接触被阻塞的线程的阻塞状态。
提示:如果你需要解除I/O操作的阻塞状态,应该使用“new I/O”库中的通道(channel)机制。当另一个线程关闭通道时,被阻塞的线程就再次变为可运行的了,而阻塞操作将抛出一个ClosedChannelException异常。


1.3.4 死线程

有两个原因会导致线程死亡:
  • 因为run方法正常退出而自然死亡;
  • 因为一个未捕获的异常终止了run方法而使线程猝死。
     
特殊情况下,你可以通过调用线程的stop方法来杀死一个线程。这个方法将抛出一个ThreadDeath出错对象来杀死线程。但是,stop方法已经过时了,你不应该在你自己的代码中调用它。

为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果线程是可运行的或者被阻塞的,这个方法返回true;否则,如果线程仍旧处于new状态且不是可运行的,或者线程死亡了,就返回false;

注意:无法确定一个活着的线程是可运行的还是被阻塞了,也无法确定一个可运行的线程是否正在运行。另外,你也无法区分线程死亡和非可运行线程。  
 API java.lang.Thread 1.0
  • boolean isAlive( ) 如果线程已经启动并且还没有被禁止,则返回true;
  • void stop( ) 停止线程。这个方法已经过时了。
  • void suspend( ) 挂起当前线程的执行过程。这个方法已经过时了。
  • void resume() 恢复线程。这个方法只能在调用suspend() 之后调用。这个方法已经过时了。
  • void join()  等待直到指定的线程死亡。
  • void join(long millis) 等待直到指定的线程死亡或经过指定的毫秒数。
原创粉丝点击