`

多线程之线程状态

阅读更多

操作系统的多任务

有两种实现多任务的方法,这取决于操作系统在中断程序时的行为——直接中断而不需要事先和被中断的程序协商,还是只有在被中断程序同意交出控制权之后才能执行中断。前者称为抢占式多任务,后者称为协作(非抢占式)多任务。抢占式多任务更加有效,但实现起来难度较大。而在协作多任务机制下,一个行为不当的程序可能会独占所有资源,导致其他所有程序无法正常工作(时说不当的程序不交出控制权,其他的线程任务无法被执行)。

多线程程序在更低的层次中引入多任务从而扩展了多任务的思想:单个程序看起来可以同时处理多个任务。通常将每个任务称为一个线程,它是控制线程的简称。可以一次运行多个线程的程序被称为多线程程序。

 

多线程和多进程的区别

本质区别在于每个进程有它自己的变量的完备集,线程则共享相同的数据。这听起来似乎有些危险,事实上也确实如此。尽管如此,对程序来说,共享的变量使线程之间的通讯比进程间的通讯更加有效而简单。而且,对于某些操作系统而言,线程比进程更“轻量级”,创建和销毁单个线程比发起进程的开销要小得多。

 

你可以通过构建一个Thread的子类来定义一个线程,然后构造一个子类的对象并调用他的start方法,然而并不建议你这样做。应该尽量从机制上减少需要并行运行的任务数。如果你有很多任务,为每个任务都创建一个独立的线程的代价就太大了,推荐使用线程池。

 

警告:不要调用Thread类或者Runnable对象的run方法。直接调用run方法只会在当前线程中执行任务,并不会启动新的线程(相当于在当前线程中的一个普通方法调用),正确的做法是调用Thread.start()方法,它会创建一个新的线程来执行run方法。

 

API:java.lang.Thread

  • static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
  • Thread(Runnable target)  构造一个新的线程来调用指定target的run方法
  • void start() 启动这个线程,将引发调用run方法。这个方法将立即返回,并且新线程将并发运行
  • void run() 调用关联的Runnable的run方法

中断线程

线程将在它的run方法返回时终止。

可以使用interrupt方法来请求终止一个线程。该方法被调用时,会发送一个中断请求给当前线程。这个线程的中断状态将被设为true。如果这个线程当前被一个sleep调用阻塞,那么将抛出一个InterruptedException异常。使用interrupt方法并不能杀死线程,他只是将线程标记为中断状态,中断状态是可能再次回到可运行状态的,请参考下文中的线程状态。

 

当interrupt方法在一个线程上被调用时,该线程的中断状态(interrupted status)将会被置位。这是一个布尔类型的标志,存在于每一个线程之中。每个线程都应该不时地检查这个标志,以判断线程是否应该被中断。为了查明中断状态是否被置位,需要首先调用静态的Thread.currentThread方法来取得当前线程,然后调用它的isInterrupted方法:

while (!Thread.currentThread().isInterrupted()) {
	//do more work
}

 

如果一个线程被阻塞(是指阻塞状态,有很多种场景可以让线程阻塞,比方说Thread的sleep或者wait方法都可以造成线程的暂时阻塞)了,他就无法检查中断状态,而且还会抛出一个InterruptedException异常。

 

Thread的sleep等方法可以造成当前线程的阻塞,因此不要在sleep方法之后调用isInterrupted方法。否则会抛异常。


警告:当sleep方法抛出一个InterruptedException异常的时候,它同时也会清除中断状态。

 

interrupted和isInterrupted两个方法的区别:

这两个方法都能用来检测线程是否处于中断状态。interrupted方法是Thread类的静态方法,调用interrupted方法后会清除当前线程的阻塞状态。而isInterrupted方法是一个实例方法,调用isInterrupted方法后不会改变中断状态的值。

 

线程状态

线程可以有以下4个状态:

  • New——新生状态
  • Runnable——可运行状态
  • Blocked——被阻塞状态
  • Dead——死亡状态

新生状态:

当使用new操作符创建一个线程时,例如:用new Thread(Runnable),线程还没有开始运行(还没有调用start方法)。此时线程处于新生状态。

 

可运行状态:

当调用start方法后,该线程就进入了可运行状态了。start方法调用后,一个可运行线程可能实际上正在运行,也可以没有被执行,这取决于操作系统为该线程提供的运行时间(也就是之前说到的操作系统的多任务机制,是抢占式的还是协作式的,可运行状态的线程可能没有抢占到执行权而没有运行)。进入可运行的状态的线程被运行以后,并不是始终保持运行时的状态,可能会在运行中被中断,目的是使其他线程获得运行机会,也可能被其他的线程抢过去执行了。

目前市面上的桌面和服务器的操作系统都是使用抢占式调度,只有一些小型设备如手机系统,可能会采用协作式调度。因此运行时的线程可能随时会被其他的线程抢占过去执行,所以我们的称这个状态为Runnable而不是Running。

 

被阻塞状态:

当发生以下任何一种情况时,线程就会进入被阻塞状态:

  • 线程通过调用sleep方法进入睡眠状态
  • 线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者
  • 线程试图得到一个锁,而该锁正被其他线程持有
  • 线程在等待某个触发条件
  • 有人调用了线程的suspend方法。该方法已过时,我们不应该在自己的代码中使用。

通过以下途径中的一种,线程可以从被阻塞状态回到可运行状态:

  • 线程被置于睡眠状态,且已经经过指定的毫秒数——睡眠时间到了,该醒了。
  • 线程正在等待I/O操作的完成,且该操作已经完成——你完成了,该我了。
  • 线程正在等待另一个线程所持有的锁,且另一个线程已经释放了该锁的所有权(也有可能等待超时,我不等了)。
  • 线程正在等待某一个触发条件,且另一个线程发出了信号表明条件已经发生变化(也有可能等待超时,我不等了)。
  • 线程已经被挂起,且有人调用了它的resume方法。和suspend方法一样,该方法已过时,我们不应该在自己的代码中使用。

一个被阻塞的线程只能通过和他先前阻塞他的相同过程重新进入可运行状态。要特别注意,不能通过调用resume方法来解除被阻塞线程的阻塞状态。也就是说,上文介绍的进入阻塞状态与回到可运行状态必须是相互对应的。

 

死亡状态:

有两个原因会导致线程死亡,如下:

  • 因为run方法正常退出而自然死亡
  • 因为一个未捕获的异常终止了run方法而使线程猝死

特殊情况下,可以通过调用线程的stop方法来杀死一个线程。该方法将抛出一个ThreadDeath出错对象来杀死线程。但stop方法已经过时,我们不应该在自己的代码中调用它。

 

如何判断当前线程是否存活(要么是可运行的,要么是被阻塞的)

可以使用isAlive方法。如果线程是可运行或者被阻塞的,该方法返回true,如果线程处于新生状态或者是死亡状态,则返回false。

 

注意:我们无法确定一个活着的线程是可运行的,还是被阻塞的,也无法确定一个可运行的线程是否正在运行。另外,你也无法区分死亡线程和非可运行线程。


参考资料:

JAVA 核心技术 卷2:高级特性

 

分享到:
评论

相关推荐

    C#多线程读写sqlite

    多线程读写sqlite数据库,同步锁,计时测试读写性能,

    基于单片机运行的多线程任务状态机.pdf

    基于单片机运行的多线程任务状态机.pdf

    [『辅助』] 易编远航第一期-六套大漠多线程中级进阶视频教程

    易大漠多线程中级之同步器子窗口设置及获取鼠标状态 5.易大漠多线程中级之同步器同步鼠标 6.易大漠多线程中级之同步器子窗口设置及获取键盘状态 7.易大漠多线程中级之同步器同步键盘  8.易大漠多线程中级之同步...

    Java线程:线程状态的转换

    初学者学习java多线程的必备良师啊!! 该文档内容简单易懂 条理清晰 !! 内容包含:线程的状态及状态之间的转换 线程的优先级 线程的几大常用方法! 申明: 本文出自 “熔 岩” 博客,本人从百度文库转载而来! 大家都...

    C#多线程之如何弹出一个模式窗口来显示进度条

    C#多线程之如何弹出一个模式窗口来显示进度条 学习版

    Java-多线程线程状态转换图

    多线程线程状态转换图

    Delphi多线程教程

    Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了。然而这并不是多线程编...

    多线程程序时序分析的隐Markov模型

    建立多线程程序时序分析的隐Markov模型,使用Baum-Welch和前向算法仿真上下文对程序实际运行状态的影响.实验结果表明,该模型能够快速有效反映多线程执行时序,用于指导多线程程序时序竞争检测过程.

    powerbuilder 实现多线程

    参考了http://blog.csdn.net/gaoqiangz/article/details/6682895以后,弄了这个演示程序,以更为简单的方式实现了多线程,主线程与子线程的双向通讯:启动子线程、查询子线程状态,中止了线程等。原理请参考上述博文...

    Java多线程(二)、线程的生命周期和状态控制

    Java多线程(二)、线程的生命周期和状态控制

    多线程机制

    3、 几个常用的改变线程状态的方法 3 4、 线程的同步机制 8 5、 死锁 11 6、 线程间通信,也叫生产者与消费者问题 15 7、 浅析 Java Thread.join() : java多线程实现主线程等待所有子线程执行完毕 16 8、 线程运行...

    Java 多线程介绍

    Java 多线程介绍 线程的几种状态 1

    linux多线程编程

    linux多线程编程 声明:本文是网上整理的资料,版权属其作者本人所有。 1 第一章 线程基础知识 2 一.什么是线程 2 二.线程的优点 2 三.线程的缺点 2 四.线程的结构 2 五.线程标识 2 六.线程的创建 3 七..线程...

    Winform实现多线程异步更新UI(进度及状态信息)

    Winform实现多线程异步更新UI(进度及状态信息) 实例代码

    linux多线程设计及示例

    当一个可汇合的线程终止时,它的线程ID和退出状态将留到另一个线程对它调用pthread_join。脱离线程却象守护进程:当它们终止的时,所有相关资源都被释放,我们不能等待它们终止。如果一个线程需要知道另一个线程什么...

    C# 多线程教材

    线程状态 等待句柄 同步环境 使用多线程 单元模式和Windows Forms BackgroundWorker类 ReaderWriterLock类 线程池 异步委托 计时器 局部储存 高级话题 非阻止同步 Wait和Pulse Suspend和Resume 终止线程 概

    Java多线程编程总结

    Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 Java线程:线程的调度-让步 Java线程:线程的调度-合并 Java线程:线程的...

    110104010104.rar_MFC多任务_MFC多线程挂起_mfc 多线程_mfc 生产者

    线程是程序独立运行的基本单位,一个程序通过执行多个线程可以提高机器本身资源的利用率,同时也可以完成多任务并行运行的操作,多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。 互斥体 互斥体与临界区...

    Linux多线程编程技术

    2.1 内核线程 ...支持多线程的内核叫做多线程 内核(Multi-Threads kernel )。内核线程的调度由内核负责,一个内核线程处于阻塞状态时不影响其他的内核线程,因为其是调度的基本单位。这与用户线程是不一样的。

    iOS多线程之NSThread详解

    iOS多线程开发一 使用NSThread NSThread的基本使用 // demo说明 NSThreadDemoOne: 简单使用多线程,区分有多线程和没有多线的区别 NSThreadDemoTwo: 因为NSThread只能传一个一个参数,如果咬传递多个参数,使用封装...

Global site tag (gtag.js) - Google Analytics