线程是如何在 6 种状态之间转换的

线程是如何在 6 种状态之间转换的

    • 线程的 6 种状态
    • New 新创建
    • Runnable 可运行
    • 阻塞状态
      • Blocked 被阻塞
      • Waiting 等待
      • Timed Waiting 限期等待
    • 注意点

主要学习线程是如何在 6 种状态之间转换。

线程的 6 种状态

就像生物从出生到长大、最终死亡的过程一样,线程也有自己的生命周期,在 Java 中线程的生命周期中一共有 6 种状态。

  1. New(新创建)
  2. Runnable(可运行)
  3. Blocked(被阻塞)
  4. Waiting(等待)
  5. Timed Waiting(计时等待)
  6. Terminated(被终止)

如果想要确定线程当前的状态,可以通过 getState() 方法,并且线程在任何时刻只可能处于 1 种状态。

New 新创建

下面我们逐个介绍线程的 6 种状态,如图所示,首先来看下左上角的 New 状态。

New 表示线程被创建但尚未启动的状态:当我们用 new Thread() 新建一个线程时,如果线程没有开始运行 start() 方法,所以也没有开始执行 run() 方法里面的代码,那么此时它的状态就是 New。而一旦线程调用了 start(),它的状态就会从 New 变成 Runnable,也就是状态转换图中中间的这个大方框里的内容。

Runnable 可运行

Java 中的 Runable 状态对应操作系统线程状态中的两种状态,分别是 Running 和 Ready,也就是说,Java 中处于 Runnable 状态的线程有可能正在执行,也有可能没有正在执行,正在等待被分配 CPU 资源。

所以,如果一个正在运行的线程是 Runnable 状态,当它运行到任务的一半时,执行该线程的 CPU 被调度去做其他事情,导致该线程暂时不运行,它的状态依然不变,还是 Runnable,因为它有可能随时被调度回来继续执行任务。

阻塞状态

接下来,我们来看下 Runnable 下面的三个方框,它们统称为阻塞状态,在 Java 中阻塞状态通常不仅仅是 Blocked,实际上它包括三种状态,分别是 Blocked(被阻塞)、Waiting(等待)、Timed Waiting(计时等待),这三 种状态统称为阻塞状态,下面我们来看看这三种状态具体是什么含义。

Blocked 被阻塞

首先来看最简单的 Blocked,从箭头的流转方向可以看出,从 Runnable 状态进入 Blocked 状态只有一种可能,就是进入 synchronized 保护的代码时没有抢到 monitor 锁,无论是进入 synchronized 代码块,还是 synchronized 方法,都是一样。

我们再往右看,当处于 Blocked 的线程抢到 monitor 锁,就会从 Blocked 状态回到Runnable 状态。

Waiting 等待

我们再看看 Waiting 状态,线程进入 Waiting 状态有三种可能性。

  1. 没有设置 Timeout 参数的 Object.wait() 方法。
  2. 没有设置 Timeout 参数的 Thread.join() 方法。
  3. LockSupport.park() 方法。

刚才强调过,Blocked 仅仅针对 synchronized monitor 锁,可是在 Java 中还有很多其他的锁,比如 ReentrantLock,如果线程在获取这种锁时没有抢到该锁就会进入 Waiting 状态,因为本质上它执行了 LockSupport.park() 方法,所以会进入 Waiting 状态。同样,Object.wait() 和 Thread.join() 也会让线程进入 Waiting 状态。

Blocked 与 Waiting 的区别是 Blocked 在等待其他线程释放 monitor 锁,而 Waiting 则是在等待某个条件,比如 join 的线程执行完毕,或者是 notify()/notifyAll() 。

Timed Waiting 限期等待

在 Waiting 上面是 Timed Waiting 状态,这两个状态是非常相似的,区别仅在于有没有时间限制,Timed Waiting 会等待超时,由系统自动唤醒,或者在超时前被唤醒信号唤醒。

以下情况会让线程进入 Timed Waiting 状态。

  1. 设置了时间参数的 Thread.sleep(long millis) 方法;
  2. 设置了时间参数的 Object.wait(long timeout) 方法;
  3. 设置了时间参数的 Thread.join(long millis) 方法;
  4. 设置了时间参数的 LockSupport.parkNanos(long nanos) 方法和 LockSupport.parkUntil(long deadline) 方法。

讲完如何进入这三种状态,我们再来看下如何从这三种状态流转到下一个状态。

想要从 Blocked 状态进入 Runnable 状态,要求线程获取 monitor 锁,而从 Waiting 状态流转到其他状态则比较特殊,因为首先 Waiting 是不限时的,也就是说无论过了多长时间它都不会主动恢复。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

只有当执行了 LockSupport.unpark(),或者 join 的线程运行结束,或者被中断时才可以进入 Runnable 状态。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果其他线程调用 notify() 或 notifyAll()来唤醒它,它会直接进入 Blocked 状态,这是为什么呢?因为唤醒 Waiting 线程的线程如果调用 notify() 或 notifyAll(),要求必须首先持有该 monitor 锁,所以处于 Waiting 状态的线程被唤醒时拿不到该锁,就会进入 Blocked 状态,直到执行了 notify()/notifyAll() 的唤醒它的线程执行完毕并释放 monitor 锁,才可能轮到它去抢夺这把锁,如果它能抢到,就会从 Blocked 状态回到 Runnable 状态。

img

同样在 Timed Waiting 中执行 notify() 和 notifyAll() 也是一样的道理,它们会先进入 Blocked 状态,然后抢夺锁成功后,再回到 Runnable 状态。

当然对于 Timed Waiting 而言,如果它的超时时间到了且能直接获取到锁/join的线程运行结束/被中断/调用了LockSupport.unpark(),会直接恢复到 Runnable 状态,而无需经历 Blocked 状态。

再来看看最后一种状态,Terminated 终止状态,要想进入这个状态有两种可能。

  • run() 方法执行完毕,线程正常退出。
  • 出现一个没有捕获的异常,终止了 run() 方法,最终导致意外终止。

注意点

最后我们再看线程转换的两个注意点。

  1. 线程的状态是需要按照箭头方向来走的,比如线程从 New 状态是不可以直接进入 Blocked 状态的,它需要先经历 Runnable 状态。
  2. 线程生命周期不可逆:一旦进入 Runnable 状态就不能回到 New 状态;一旦被终止就不可能再有任何状态的变化。所以一个线程只能有一次 New 和 Terminated 状态,只有处于中间状态才可以相互转换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/277652.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搭建Hadoop3.x完全分布式集群

零、资源准备 虚拟机相关: VMware workstation 16:虚拟机 > vmware_177981.zipCentOS Stream 9:虚拟机 > CentOS-Stream-9-latest-x86_64-dvd1.iso Hadoop相关 jdk1.8:JDK > jdk-8u261-linux-x64.tar.gzHadoop 3.3.6&am…

Netty架构详解

文章目录 概述整体结构Netty的核心组件逻辑架构BootStrap & ServerBootStrapChannelPipelineFuture、回调和 ChannelHandler选择器、事件和 EventLoopChannelHandler的各种ChannelInitializer类图 Protocol Support 协议支持层Transport Service 传输服务层Core 核心层模块…

第七节:Vben Admin权限-后端获取路由和菜单

系列文章目录 第一节:Vben Admin介绍和初次运行 第二节:Vben Admin 登录逻辑梳理和对接后端准备 第三节:Vben Admin登录对接后端login接口 第四节:Vben Admin登录对接后端getUserInfo接口 第五节:Vben Admin权限-前端控制方式 第六节:Vben Admin权限-后端控制方式 第七节…

Unity2019.2.x 导出apk 安装到安卓Android12+及以上的系统版本 安装出现-108 安装包似乎无效的解决办法

Unity2019.2.x 导出apk 安装到安卓Android12及以上的系统版本 安装出现-108 安装包似乎无效的解决办法 导出AndroidStudio工程后 需要设置 build.gradle文件 // GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAINbuildscript {repositor…

河马优化算法(HO)-2024年Nature子刊新算法 公式原理详解与性能测评 Matlab代码免费获取

声明:文章是从本人公众号中复制而来,因此,想最新最快了解各类智能优化算法及其改进的朋友,可关注我的公众号:强盛机器学习,不定期会有很多免费代码分享~ 目录 原理简介 一、种群初始化 二、河马在河流或…

【Python编程基础】第一节.Python基本语法(上)

文章目录 前言⼀、Python介绍二、Python环境配置三、Pycharm 书写代码四、Python基本语法 4.1 print 函数的简单使用 4.2 注释 4.3 Python 代码中三种波浪线和 PEP8 4.4 在 cmd 终端中运⾏ Python 代码 4.5 变量 4.6 数据类型 4.7 类型转换…

Python使用openpyxl库或pandas库创建.xlsx格式的Excel文件,并向文件不同的sheet按行或按列写入内容

import openpyxl# 创建-一个Workbook对象 wb openpyxl.Workbook()# 创建多个工作表 sheet1 wb.active sheet1.title "s1"sheet2 wb.create_sheet("s2")# 在不同的工作表中写入数据 sheet1["A1"] Data for Sheet1 sheet1["A2"] D…

HCIP—BGP邻居关系建立实验

BGP的邻居称为:IBGP对等体 EBGP对等体 1.EBGP对等体关系: 位于 不同自治系统 的BGP路由器之间的BGP对等体关系 EBGP对等体一般使用 直连建立 对等体关系,EBGP邻居之间的报文 TTL中值设置为1 两台路由器之间建立EBGP对等体关系&#xff0…

SQLiteC/C++接口详细介绍之sqlite3类(十三)

返回目录:SQLite—免费开源数据库系列文章目录 上一篇:SQLiteC/C接口详细介绍之sqlite3类(十二) 下一篇:SQLiteC/C接口详细介绍之sqlite3类(十四)(未发表) 40.sqlite3…

【算法】一类支持向量机OC-SVM(1)

【算法】一类支持向量机OC-SVM 前言一类支持向量机OC-SVM 概念介绍示例编写数据集创建实现一类支持向量机OC-SVM完整的示例输出 前言 由于之前毕设期间主要的工具就是支持向量机,从基础的回归和分类到后来的优化,在接触到支持向量机还有一类支持向量机的…

Redis Desktop Manager:一站式Redis数据库管理与优化

Redis Desktop Manager是一款功能强大的Redis桌面管理工具,也被称作Redis可视化工具。以下是其主要的功能特色: 连接管理:Redis Desktop Manager支持连接多个Redis服务器,用户可以在同一界面下管理多个数据库,大大提高…

通用的springboot web jar包执行脚本,释放端口并执行jar包

1、通用的springboot web jar包执行脚本,释放端口并执行jar包: #!/bin/bash set -eDATE$(date %Y%m%d%H%M) # 基础路径 BASE_PATH/data/yitu-projects/yitu-xzhq/sftp # 服务名称。同时约定部署服务的 jar 包名字也为它。 SERVER_NAMEyitu-server # 环境…

数据仓库数据分层详解

数据仓库中的数据分层是一种重要的数据组织方式,其目的是为了在管理数据时能够对数据有一个更加清晰的掌控。以下是数据仓库中的数据分层详解: 原始数据层(Raw Data Layer):这是数仓中最底层的层级,用于存…

计算机二级Python题目13

目录 1. 基本题 1.1 基本题1 1.2 基本题2 1.3 基本题3 2. turtle画图 3. 大题 3.1 大题1 3.2 大题2 1. 基本题 1.1 基本题1 lseval(input()) s"" for item in ls:if type(item)type("香山"):s item print(s) 1.2 基本题2 import random random.se…

android MMKV数据持久化缓存集合

前言 最近在使用mmkv缓存的时候 发现没有集合缓存 非常不方便 自己写一个方法 MMKV public class MmkvUtils {private MmkvUtils() {throw new UnsupportedOperationException("u cant instantiate me...");}public static void init() {MMKV.initialize(LeoUtils…

RTP 控制协议 (RTCP) 反馈用于拥塞控制

摘要 有效的 RTP 拥塞控制算法,需要比标准 RTP 控制协议(RTCP)发送方报告(SR)和接收方报告(RR)数据包提供的关于数据包丢失、定时和显式拥塞通知 (ECN) 标记的更细粒度的反馈。 本文档描述了 RTCP 反馈消息,旨在使用 RTP 对交互式实时流量启用拥塞控制…

【安全类书籍-3】XSS跨站脚剖析与防御

目录 内容简介 作用 下载地址 内容简介 这本书涵盖以下几点: XSS攻击原理:解释XSS是如何利用Web应用未能有效过滤用户输入的缺陷,将恶意脚本注入到网页中,当其他用户访问时被执行,实现攻击者的目的,例如窃取用户会话凭证、实施钓鱼攻击等。 XSS分类:分为存储型XSS(…

【热门话题】前端框架发展史

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 前端开发的历史演变引言第一章:起源与基础建设 - HTML与CSS时代1.1 …

蓝桥杯刷题(九)

1.三国游戏 代码 #输入数据 nint(input()) Xlilist(map(int,input().split())) Ylilist(map(int,input().split())) Zlilist(map(int,input().split())) #分别计算X-Y-Z/Y-Z-X/Z-X-Y并排序 newXli sorted([Xli[i] - Yli[i] - Zli[i] for i in range(n)],reverseTrue) newYli …

C#控制台贪吃蛇

Console.Write("");// 第一次生成食物位置 // 随机生成一个食物的位置 // 食物生成完成后判断食物生成的位置与现在的蛇的身体或者障碍物有冲突 // 食物的位置与蛇的身体或者障碍物冲突了,那么一直重新生成食物,直到生成不冲突…