前提介绍

本章主要介绍相关线程声明周期的转换机制以及声明周期的流转关系以及相关AQS的实现和相关的基本原理,配合这相关官方文档的中英文互译的介绍。

线程状态流转及生命周期

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪/可运行状态(Runnable)、阻塞(Blocked)和等待(Wait)、时间等待(Time_wait)、终止状态(Terminate)六种状态。尤其是当线程启动以后,它不能一直“霸占”着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。

下图借鉴于官方网站:

生命周期的六种状态

一个事物从出生的那一刻开始到最终死亡中间的整个过程.在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态/中年状态/老年状态...).线程也是有生命周期的,也是存在不同的状态的,状态相互之间的转换。

线程对象的状态存放在Thread类的内部类(State)中:

 public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW, /**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE, /**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED, /**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING, /**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING, /**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}

注意:Thread.State类其实是一个枚举类.因为线程对象的状态是固定的,只有6种,此时使用枚举来表示是。


新建(new Thread)
  • 当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。

  • 使用new创建一个线程对象,仅仅在堆中分配内存空间,在调用start方法之前。 新建状态下,线程压根就没有启动,仅仅只是存在一个线程对象而已.Thread t = new Thread();

  • 此时t就属于新建状态当新建状态下的线程对象调用了start方法,此时从新建状态进入可运行状态.线程对象的start方法只能调用一次,否则报错:IllegalThreadStateException.

例如
Thread  t1=new Thread();

可运行(runnable)

分成两种子状态,ready和running。分别表示就绪状态和运行状态。

就绪状态

线程对象调用start方法之后,等待JVM的调度(此时该线程并没有运行),这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行,换句话说线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。

运行状态

线程对象获得JVM调度,如果存在多个CPU,那么允许多个线程并行运行

  • 被转换成Terminated状态,比如调用 stop() 方法;

  • 被转换成Blocked状态,比如调用了sleep, wait 方法被加入 waitSet 中;

  • 被转换成Blocked状态,如进行 IO 阻塞操作,如查询数据库进入阻塞状态;

  • 被转换成Blocked状态,比如获取某个锁的释放,而被加入该锁的阻塞队列中;

  • 该线程的时间片用完,CPU 再次调度,进入Runnable状态;

  • 线程主动调用 yield 方法,让出 CPU 资源,进入Runnable状态

例如
t1.start();
运行(running)他也从属于Runnable状态,但不在总体状态之内,属于逻辑状态机制

当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能,此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

注意:

Runnable状态的线程无法直接进入Blocked状态和Terminated状态的。只有处在Running状态的线程,换句话说,只有获得CPU调度执行权的线程才有资格进入Blocked状态和Terminated状态,Runnable状态的线程要么能被转换成Running状态,要么被意外终止。

堵塞(blocked)

正在运行的线程因为某些原因放弃CPU,暂时停止运行,就会进入阻塞状态.此时JVM不会给线程分配CPU,直到线程重新进入就绪状态,才有机会转到运行状态.阻塞状态只能先进入就绪状态,不能直接进入运行状态。

阻塞状态的两种情况:
  1. 当A线程处于运行过程时,试图获取同步锁时,却被B线程获取.此时JVM把当前A线程存到对象的锁池中,A线程进入阻塞状态.
  2. 当线程处于运行过程时,发出了IO请求时,此时进入阻塞状态.

由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

  • 被转换成Terminated状态,比如调用 stop() 方法,或者是 JVM 意外 Crash;

  • 被转换成Runnable状态,阻塞时间结束,比如读取到了数据库的数据后;

  • 完成了指定时间的休眠,进入到Runnable状态;

  • 正在wait中的线程,被其他线程调用notify/notifyAll方法唤醒,进入到Runnable状态;

  • 线程获取到了想要的锁资源,进入Runnable状态;

  • 线程在阻塞状态下被打断,如其他线程调用了interrupt方法,进入到Runnable状态;

等待状态(waiting)

(等待状态只能被其他线程唤醒):

此时使用的无参数的wait方法,

  1. 当线程处于运行过程时,调用了wait()方法,此时JVM把当前线程存在对象等待池中.
计时等待状态(timed waiting)

(使用了带参数的wait方法或者sleep方法)

  1. 当线程处于运行过程时,调用了wait(long time)方法,此时JVM把当前线程存在对象等待池中.
  2. :当前线程执行了sleep(long time)方法.
终止状态(terminated)

通常称为死亡状态,表示线程终止.

  1. 正常执行完run方法而退出(正常死亡).
  2. 遇到异常而退出(出现异常之后,程序就会中断)(意外死亡).
  3. JVM 异常结束,所有的线程生命周期均被结束。

线程一旦终止,就不能再重启启动,否则报错(IllegalThreadStateException).

不推荐使用的线程方法

在Thread类中过时的方法(因为存在线程安全问题,所以弃用了):

  • void suspend() :暂停当前线程
  • void resume() :恢复当前线程
  • void stop() :结束当前线程

给大家结合官网在进行一个中文解释的状态流转图:

☕【Java技术指南】「难点-核心-遗漏」Java线程状态流转及生命周期的技术指南(知识点串烧)!的更多相关文章

  1. 🏆【JVM技术专区】「难点-核心-遗漏」TLAB内存分配+锁的碰撞(技术串烧)!

    JVM内存分配及申请过程 当使用new关键字或者其他任何方式进行创建一个类的对象时,JVM虚拟机需要为该对象分配内存空间,而对象的大小在类加载完成后已经确定了,所以分配内存只需要在Java堆中划分出一 ...

  2. ☕【JVM技术指南】「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"【下部】

    承接上文 (完结撒花1-52系列)[JVM技术指南]「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"[上部] 并行收集器 并行收集器(也称为吞吐量收集器)是类似 ...

  3. WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇]

    原文:WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇] 在[第2篇]中,我们深入剖析了单调(PerCall)模式下WCF对服务实例生命周期的控制,现在我们来 ...

  4. Java多线程——线程的优先级和生命周期

    Java多线程——线程的优先级和生命周期 摘要:本文主要介绍了线程的优先级以及线程有哪些生命周期. 部分内容来自以下博客: https://www.cnblogs.com/sunddenly/p/41 ...

  5. 🏆【Java技术专区】「探针Agent专题」Java Agent探针的技术介绍(1)

    前提概要 Java调式.热部署.JVM背后的支持者Java Agent: 各个 Java IDE 的调试功能,例如 eclipse.IntelliJ : 热部署功能,例如 JRebel.XRebel. ...

  6. 「物流跟踪管理系统」 · Java Swing + MySQL JDBC开发,美和易思结业考试机试试题

    目录 文档说明: 一.语言和环境 二.技术要求 三.功能要求 四.数据库设计 五.具体要求及推荐实现步骤 六.注意事项 实现代码: 一.数据库 二.Java Swing com.ynavc.Bean ...

  7. java EE技术体系——CLF平台API开发注意事项(4)——API生命周期治理简单说明

    文档说明 截止日期:20170905,作者:何红霞,联系方式:QQ1028335395.邮箱:hehongxia626@163.com 综述 有幸加入到javaEE技术体系的研究与开发,也得益于大家的 ...

  8. Java多线程2:线程的使用及其生命周期

    一.线程的使用方式 1.继承Thread类,重写父类的run()方法 优点:实现简单,只需实例化继承类的实例,即可使用线程 缺点:扩展性不足,Java是单继承的语言,如果一个类已经继承了其他类,就无法 ...

  9. JAVA知识积累 JSP第一篇【JSP介绍、工作原理、生命周期、语法、指令、行为】

    什么是JSP JSP全名为Java Server Pages,java服务器页面.JSP是一种基于文本的程序,其特点就是HTML和Java代码共同存在! 为什么需要JSP JSP是为了简化Servle ...

随机推荐

  1. Easyui设置easyui-textbox不可编辑

    转载自:https://blog.csdn.net/qq_23113521/article/details/78801689 在easyui里由于easyui-textbox被封装,通过一般的jque ...

  2. xmind8-update9 安装破解激活教程

    xmind8是一款原型图设计流行的软件,相比于xmind2020功能更为丰富,比如画甘特图等.本教程来教大家如何对xmind8 update9进行安装激活,使用全部功能,无限期使用! 只看本文一篇即可 ...

  3. Python - 详解 range()

    介绍 range 是一个类,不是函数 表示不可变的数字序列,通常用于在 for 循环中循环指定的次数 两种语法格式 range(stop) 表示区间 [0, stop) 内的整数序列 该区间从 0 开 ...

  4. js之检测浏览器

    getBrowser () { let ua = navigator.userAgent.toLocaleLowerCase() let browserType = null if (ua.match ...

  5. Spring Cloud分区发布实践(6)--灰度服务-根据Header选择实例区域

    此文是一个完整的例子, 包含可运行起来的源码. 此例子包含以下部分: 网关层实现自定义LoadBalancer, 根据Header选取实例 服务中的Feign使用拦截器, 读取Header Feign ...

  6. 为什么说使用 Linux 系统学习 OpenGL 更方便

    前言 上一篇随笔介绍了我的电脑,同时也介绍了 Ubuntu 20.10 系统的安装和美化.这一篇,我将正式开始 OpenGL 之旅.使用 Ubuntu 来进行开发,不仅仅只是因为我对 Linux 桌面 ...

  7. fiddler抓https包教程

    第一步: 安装fiddler 第二步: 下载fiddler证书生成器 第三步: 进入fiddler导出证书 第四步: 打开浏览器导入证书 第一步:安装fiddler  安装方法各位随意,但需保证是最新 ...

  8. Java知识复习回顾

    1.MVC 三层架构: M:Model 数据模型层 V:View 视图层 C:Controller控制器层 目的:解耦 2.Spring Spring:轻量级的Java开源框架,容器,目的是解决企业级 ...

  9. 《高性能利器》-32张图带你解决RocketMQ所有场景问题

    一.RocketMQ的基本原理 RocketMQ基本架构图如下 从这个架构图上我们可以知道,RocketMQ有4块核心部分: NameServer:管理Broker的信息,让使用MQ的系统感知到集群里 ...

  10. Linux中DNS分离解析

    目录 一.分离解析概述 二.DNS分离解析实验 要求 实验步骤 一.分离解析概述 分离解析:同一个dns服务器,同一个域名情况下,不同网段进行访问会解析出不同的IP地址 分离解析的域名服务器实际也是主 ...