线程与操做系统中线程(进程)的概念同根同源,尽管千差万别。
操做系统中有状态以及状态的切换,Java线程中照样也有。
State
在Thread类中有内部类 枚举State,用于抽象描述Java线程的状态,共有6种不一样的状态
详细定义以下:
public enum State { html
/** 编程
* 至今还没有启动的线程的状态。 多线程
*/ less
NEW, spa
/** 操作系统
* 可运行线程的线程状态。 线程
* 处于可运行状态的某一线程正在 Java 虚拟机中运行,但它可能正在等待操做系统中的其余资源,好比处理器。 3d
*/ htm
RUNNABLE, 对象
/**
* 受阻塞而且正在等待监视器锁的某一线程的线程状态。
* 处于受阻塞状态的某一线程正在等待进入一个同步的块/方法的监视器锁,或者在调用 Object.wait 以后再次进入同步的块/方法。
*/
BLOCKED,
/**
* 某一等待线程的线程状态。
* 某一线程由于调用下列方法之一而处于等待状态:
* 不带超时值的 Object.wait
* 不带超时值的 Thread.join
* LockSupport.park
* 处于等待状态的线程正等待另外一个线程,以执行特定操做。
* 例如,已经在某一对象上调用了 Object.wait() 的线程正等待另外一个线程,以便在该对象上调用 Object.notify() 或 Object.notifyAll()。
* 已经调用了 Thread.join() 的线程正在等待指定线程终止。
*/
WAITING,
/**
* 具备指定等待时间的某一等待线程的线程状态。
* 某一线程由于调用如下带有指定正等待时间的方法之一而处于定时等待状态:
* Thread.sleep
* 带有超时值的 Object.wait
* 带有超时值的 Thread.join
* LockSupport.parkNanos
* LockSupport.parkUntil
*/
TIMED_WAITING,
/**
* 已终止线程的线程状态。线程已经结束执行。
*/
TERMINATED;
}
状态详解
NEW
当一个线程建立后,也就是new了一个Thread,那么这个Thread的state就是NEW
有且只有这种状况下,才为NEW,不会从任何状态转换而来
也就是说若是一个线程状态已经再也不是NEW,那么他永远不可能再从新回到NEW的状态,这是一个起点
下面的示例中建立了一个线程myThread,并无调用start方法
TERMINATED
当一个线程终止后,就进入状态TERMINATED
TERMINATED做为线程的终点,一旦进入TERMINATED状态,将再也不可以转换为其余状态
下面的示例中,建立了一个线程myThread,而且调用start方法启动
而后主线程(当前线程)sleep 1秒(确保myThread确定结束了),而后查看myThread的状态,很显然,此时已经进入终止状态
NEW和TERMINATED分别对应线程生命周期的起点和终点
对于NEW来讲,一旦离开,就永远回不来了;
对于TERMINATED来讲,一旦到达, 就永远回不去了;
RUNNABLE
RUNNABLE用于表示可运行状态
下面的代码在主线程中运行,运行过程当中是RUNNABLE状态
API中有说到:“处于可运行状态的某一线程正在 Java 虚拟机中运行,但它可能正在等待操做系统中的其余资源,好比处理器。”
也就是说一个RUNNABLE并非必定正在运行
若是咱们将线程运行全部的资源与条件分为两种:CPU时间片以及除了时间片之外的全部其余;
一旦进入RUNNABLE状态,那么他确定已经拥有了“除了时间片之外的全部其余资源”
可是,是否正在被执行?这个不肯定,还要看是否被分配了时间片
若是没有处理器资源(时间片)那么就是“准备稳当”状态,若是分配了处理器资源(时间片),那么就是“正在运行”状态。
因此RUNNABLE状态能够细分为两种状态:准备稳当(READY)与RUNNING(正在运行)
可是,为何没有将RUNNABLE细分?
很显然,对于开发者来讲可以作到的就是“除了时间片之外的全部其余资源”,而对于操做系统处理器CPU时间片的调度,是彻底没有能力操控的(yield也只是提示)
因此,从应用的角度看,也就只有RUNNABLE状态,一个RUNNABLE的线程,他随时可能在运行,也可能在等待调度。
等待状态
BLOCKED、WAITING、TIMED_WAITING三种状态相对前面的几种,相对稍微复杂一点,由于会涉及到各类切换
对照着汉字来讲,这三者都有“等”的意思,可是却又不太相同
举几个例子感觉一下
当你发现前方信号灯转变为红灯时,你停车等待;
当你通过斑马线时,正好有行人通过,你停车等待;
当售票窗口中午休息时,你原地等待;
这几种等待更多的是由于不可抗力,不得不等的一种场景,BLOCKED更接近这种等待;
对于临界资源的访问,须要互斥访问,Java中使用对象监视器做为锁,想要进入同步区域,就须要得到对应的监视器锁
若是获取不到,就须要等待,这就是BLOCKED状态;
要出门时,你老婆说我化个妆,你等我下;
买水果时,售货员说刚卖完了,师傅去仓库去取了,您稍等一下;
此时的等,是在等一件事情的发生,WAITING更接近这种等待;
虽然都是在等待,卡住不能动,仍是等一等,仍是有区别的;
TIMED_WAITING与WAITING就比较类似了,他们的区别,从汉语的角度理解相似“你等我两分钟和你等一会”的区别
等两分钟有时间,等一下子不肯定到底等待多大一下子
再回到Java线程中,能够认为:
- 若是一个线程在等待获取进入同步区域的监视器锁,那么是BLOCKED;
- 若是线程调用了不带超时值的等待方法,好比 Object.wait,持续等待某件事情的发生,直到收到通知,那么是WAITING
- 若是线程调用了好比带有超时值的等待方法,好比wait(long timeout),进行必定时间的等待,到到时间后将再也不等待,那么是TIMED_WAITING
状态转换图
换一个角度理解,线程状态的切换
下图从前驱和后继的角度分析了线程状态的变化
以中间一列为中心
状态对比
既然操做系统中线程概念模型有状态切换,Java线程也有状态,他们有何异同?
如上图所示,操做系统中的进程、线程模型的状态
核心为就绪(ready)阻塞(waiting)执行(run)
而对于Java线程中
核心状态为RUNNABLE、BLOCKED、WAITING、TIMED_WAITING(项目中根本不会建立线程,会借助于线程池,因此NEW和TERMINATED非重点)
Java线程为操做系统原生线程的映射,状态上也是有所映射的
Runnable状态,则对应了操做系统中的就绪(ready)和执行(run)
TIMED_WAITING ,WAITING仍是BLOCKED,对应的都是操做系统线程的阻塞(waiting)状态
须要注意的是:这些状态是虚拟机状态,它不反映任何操做系统的线程状态,能够查看State的注释
为何状态没有对应?
咱们以前在说起线程的实现时,就有说到用户级和内核支持的对比,内核支持的是依靠操做系统来调度的,1.2以后就是对操做系统线程的映射
因此,既然调度依赖的是操做系统,那么,操做系统底层的状态对于开发者来讲就不是那么必要了,由于你并不能对他进行事无巨细的控制
JVM中的线程是操做系统底层线程的映射,既然是映射,能够认为是一个薄层封装
封装的目的是为了更好的符合Java多线程编程的模型,而不是要原模原样的去照搬
从这一点也能更好地理解,为何RUNNABLE至关于READY和RUNNING,由于JVM原本就只能作到这一步,READY仍是RUNNING,搞不了,那还提供这两个状态干什么呢?
因此记住:
JVM中的状态只是Java的多线程模型中的状态,并不反应任何操做系统的线程状态
JVM中的状态与底层操做系统中线程的状态也没有必要去映射