当前位置: 首页 > news >正文

【JavaEE】线程状态

目录

前言

一.线程状态图

二.线程状态

1.初始状态(NEW)

 2.运行状态(RUNNING)

 3.等待状态(WAITING)

4.超时等待(TIMED_WAITING)

5.阻塞状态(BLOCKED)

 6.终止状态(TERMINATED)

 三.线程状态间的转换

四.总结 


前言

线程状态及其状态转换是线程生命周期中的关键部分,下面我们就来讲解六种线程状态以及其如何转换。

一.线程状态图

线程状态其实是一种枚举类型Thread.State

class T_state{public static void main(String[] args) {for(Thread.State state:Thread.State.values()){System.out.println(state);}}
}

 

  • NEW(初始):创建了一个线程,但还没有通过start方法调用。可以理解为安排了工作,但还没有开始工作。
  • RUNNABLE(运行):又分为Ready(就绪状态)Running(运行中状态)

当线程对象被创建之后,若有线程(比如main线程)调用了该线程对象的start,那么该线程就会进入可运行线程池进行等待线程调用,获取CPU的使用权,此时就处于Ready(就绪状态),当获取到cpu使用权之后,就转变为Running(运行中状态)。

Ready可以理解为即将开始工作,而Running即正在工作中。

  • BLOCKED(阻塞):线程试图获取一个锁对象,但此时锁对象被其他线程所占有,那么线程就进入阻塞等待,当获取到锁,则进入Running状态。
  • WAITING(等待):线程处于等待状态,等待其他线程唤醒,可以通过notify或者notifyAll方法来唤醒。
  • TIMED_WAITING(超时等待):可以在指定的时间内返回。可以使用带参数的sleep或者wait。
  • TERMINATED(终止):线程执行结束。主线程和子线程互不影响,子线程并不会因为主线程结束就结束。

二.线程状态

1.初始状态(NEW)

new关键字新建一个线程对象,这个线程就处于new状态

public static void main(String[] args) {// 创建一个线程,该线程在执行时会暂停1000毫秒Thread t=new Thread(()->{try {Thread.sleep(1000); // 模拟线程执行的延迟} catch (InterruptedException e) {e.printStackTrace(); // 处理线程被中断的异常}});System.out.println("t的线程状态:"+t.getState()); // 输出线程的当前状态}
t的线程状态:NEW

 2.运行状态(RUNNING)

分为RUNNING(运行状态)Ready(就绪状态).

  public static void main(String[] args) {Thread t=new Thread(()->{try {Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}});t.start();System.out.println("t的线程状态:"+t.getState()); // 输出线程的当前状态}
t的线程状态:RUNNABLE

 3.等待状态(WAITING)

等待状态下,没有时间限制,等被notify或者notifyAll唤醒

 public static void main(String[] args) throws InterruptedException {// 获取当前线程对象,用于后续检查线程状态Thread mainT=Thread.currentThread();// 使用lambda表达式创建一个新的线程,该线程用于展示线程的运行和状态检查Thread t=new Thread(()->{try {// 使新线程睡眠1秒,模拟耗时操作Thread.sleep(1000);}catch (InterruptedException e){// 如果线程在睡眠时被中断,打印异常信息e.printStackTrace();}// 输出线程的当前状态System.out.println("main线程状态:"+mainT.getState());});// 启动新线程,使其开始执行t.start();// 主线程等待新线程完成t.join();}
main线程状态:WAITING

4.超时等待(TIMED_WAITING)

TIMED_WAITING线程在等待唤醒,但设置了时限,当到达时限,会自动唤醒线程。

 public static void main(String[] args) throws InterruptedException {// 创建一个线程,该线程执行一个lambda表达式,使线程睡眠1秒Thread t = new Thread(() -> {try {Thread.sleep(1000); // 线程睡眠1000毫秒} catch (InterruptedException e) {e.printStackTrace(); // 捕获InterruptedException异常并打印堆栈跟踪}});t.start();//让main线程休眠Thread.sleep(50);System.out.println(t.getState());}
TIMED_WAITING

5.阻塞状态(BLOCKED)

 当进入到synchronized关键字修饰的方法或者代码块时,线程处于阻塞状态。

示例:两个线程争同一个锁对象,此时会引起锁竞争,没有获取到锁的线程,会进入阻塞状态,等待拿到锁的线程将锁释放。

   public static void main(String[] args) {final Object o=new Object();Thread t=new Thread(()->{synchronized (o) {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});Thread tt=new Thread(()->{synchronized (o) {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});t.start();tt.start();System.out.println("t的线程状态:"+t.getState()); // 输出线程的当前状态System.out.println("tt的线程状态:"+tt.getState()); // 输出线程的当前状态}
t的线程状态:RUNNABLE
tt的线程状态:BLOCKED

 6.终止状态(TERMINATED)

当线程执行结束,就处于终止状态。

需要注意:主线程和子线程互不影响,子线程并不会因为主线程结束就结束

/*** 程序入口* @param args 命令行参数* @throws InterruptedException 如果线程被中断*/public static void main(String[] args) throws InterruptedException {// 创建一个线程,该线程将休眠1秒Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}});// 启动线程t.start();// 等待线程结束t.join();// 输出线程的状态System.out.println(t.getState());}
TERMINATED

 三.线程状态间的转换

1.创建一个线程处于new,让其转换为running状态。可以看到线程t的状态为

NEW->RUNNING->TERMINATED

 public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}});System.out.println("t线程的状态"+t.getState());t.start();System.out.println("t线程的状态"+t.getState());t.join();System.out.println("t线程的状态"+t.getState());}
t线程的状态NEW
t线程的状态RUNNABLE
t线程的状态TERMINATED

2.将处于running的线程转换为wait 。(调用wait或者join都可)

 这里以join为例。

 public static void main(String[] args) throws InterruptedException {Thread main = Thread.currentThread();Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("main线程状态:"+main.getState());});t.start();System.out.println("main线程状态:"+main.getState());t.join();}
main线程状态:RUNNABLE
main线程状态:WAITING

wait方法:一般在synchronized修饰的代码块或者方法中使用。

调用wait会发生两件事:

(1)线程解锁“锁对象” (2)被解锁的线程会进入waiting状态。 

在使用wait方法时,需要先对线程加锁,否则会报错。因为wait会先解锁再进入等待状态

示例:

 public static void main(String[] args) throws InterruptedException {final Object locker = new Object();Thread t1=new Thread(()->{synchronized (locker){try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}},"t1");t1.start();System.out.println("t线程的状态"+t1.getState());Thread.sleep(50);System.out.println("t线程的状态"+t1.getState());}
t线程的状态RUNNABLE
t线程的状态WAITING

 但如果我们使用wait带参数的方法,那么状态还会是WAITING吗?

  public static void main(String[] args) throws InterruptedException {final Object locker = new Object();Thread t1=new Thread(()->{synchronized (locker){try {locker.wait(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"t1");t1.start();System.out.println("t线程的状态"+t1.getState());Thread.sleep(50);System.out.println("t线程的状态"+t1.getState());}
t线程的状态RUNNABLE
t线程的状态TIMED_WAITING

可以看到,当我们使用带参数的wait方法时,此时t的状态转变为TIMED_WAITING

3.若多个线程尝试获取同一个锁,那么就会引起对锁的竞争,即"锁竞争”。没用获取到线程的锁将会进入阻塞状态(BLOCKED),等线程获取到锁,才能执行。

示例:

    /*** 主函数,演示线程间的状态变化* @param args 命令行参数* @throws InterruptedException 当线程被中断时抛出此异常*/public static void main(String[] args) throws InterruptedException {// 创建一个对象作为锁final Object locker = new Object();// 创建线程t1,使用锁对象进行同步操作Thread t1=new Thread(()->{// 使用锁进行同步控制,形成死循环synchronized (locker){while(true){;}}},"t1");// 启动线程t1t1.start();// 输出线程t1的当前状态System.out.println("t1线程的状态"+t1.getState());// 创建线程t2,也使用锁对象进行同步操作Thread t2=new Thread(()->{// 使用锁进行同步控制,但没有进行循环,所以很快释放锁synchronized (locker){;}},"t2");// 启动线程t2t2.start();// 输出线程t2的当前状态System.out.println("t2线程的状态"+t2.getState());// 主线程等待50毫秒,以观察线程t2的状态变化Thread.sleep(50);// 再次输出线程t2的当前状态,以观察其变化System.out.println("t2线程的状态"+t2.getState());}
t1线程的状态RUNNABLE
t2线程的状态RUNNABLE
t2线程的状态BLOCKED

我们可以打开jconsole进行查看。

四.总结 

 

当我们创建一个线程对象时,此时线程就处于NEW状态。

调用start方法,会让线程进行运行状态,其中又分为RUNNING(运行中状态)和Ready(就绪状态)。

若想要让RUNNABLE中的线程进入WAITING(等待状态),可以使用wait或者join方法。想唤醒WAITING中的线程,需要使用notify或者nofityAll方法来唤醒。

可以使用带参数的join、sleep和wait方法,让RUNNABLE中的线程进入限时等待(TIMED_WAITING),当达到时时限,会自动唤醒线程。

 RUNNABLE中的线程若想出发BLOCKED状态,需要触发锁竞争

当线程中线程体的内容都执行完之后,就会进入TERMINATED(终止状态)


线程状态的讲解就先到这里了~

若有不足,欢迎指正~

相关文章:

【JavaEE】线程状态

目录 前言 一.线程状态图 二.线程状态 1.初始状态(NEW) 2.运行状态(RUNNING) 3.等待状态(WAITING) 4.超时等待(TIMED_WAITING) 5.阻塞状态(BLOCKED) 6.终止状态(TERMINATED) 三.线程状态间的转换 四.总结 前言 线程状态及其状态转换…...

C++笔记之编译过程和面向对象

回顾: “abcd”//数据类型 字符串常量 const char *p"abc"; new STU const char *//8 指针的内存空间 int float 指针的内存空间 p 指针指向的内存空间 "abc" 取决于字符串长度 指针变量的内容一级指针 指针变量的地址二级指针 …...

ModuleNotFoundError: No module named ‘tqdm‘

报错信息: tqdm是一个快速、可扩展的Python进度条库,用于展示迭代器的长循环执行进度。 解决:通过以下命令安装 使用conda命令安装 conda install tqdm使用pip安装: pip install tqdm...

东京电影节公布2024年竞赛片评审团成员并对其业绩分别进行评介 没什么含金量

第37届东京国际电影节竞赛单元评审团名单正式公布。 周五,电影节组织者宣布,香港电影制片人杜琪峰、匈牙利电影制片人伊尔迪科恩耶迪、日本女演员桥本爱和法国女演员基娅拉马斯楚安尼将与之前宣布的评审团主席梁朝伟一起担任 2024 年主竞赛评审团成员。 …...

智能景区垃圾识别系统:基于YOLO的深度学习实现

基于深度学习的景区垃圾识别系统(UI界面YOLOv8/v7/v6/v5代码训练数据集) 1. 引言 景区垃圾识别是环保管理的重要任务之一。传统的人工清理方式效率低、成本高,而借助深度学习技术可以实现自动化的垃圾检测与识别,提高景区的清洁…...

ventoy和微pe可以共存吗?ventoy和pe共存使用教程

Ventoy新一代多系统启动U盘解决方案。国产开源U盘启动制作工具,支持Legacy BIOS和UEFI模式,理论上几乎支持任何ISO镜像文件,支持加载多个不同类型的ISO文件启动,无需反复地格式化U盘,插入U盘安装写入就能制作成可引导的…...

如何获取和安装SSL证书

SSL(Secure Sockets Layer)证书是用于加密网站服务器和客户端之间通信的一种数字证书。它通过HTTPS协议保护数据传输的安全性,防止数据被窃听或篡改。本文将指导您如何为您的网站获取并安装SSL证书。 步骤1:选择SSL证书提供商 首…...

makefile在IC设计中的使用笔记

1 makefile在IC设计中的地位 关于makefile的详细介绍可以参考第一个连接,里面的内容很多也很详细。但在数字IC设计中,并不会把所有的用法都用到,下面记录一下主要用到的规则。 2 IC设计涉及到的主要用法 2.1 变量的定义和使用 在makefile…...

Suno声称在受版权保护的音乐上训练模型属于“合理使用“

继美国唱片业协会(RIAA) 最近对音乐生成初创公司 Udio 和 Suno 提起诉讼之后,Suno 在周四提交的一份法庭文件中承认,该公司确实使用了受版权保护的歌曲来训练其人工智能模型。但它声称,根据合理使用原则,这…...

Java | Leetcode Java题解之第316题去除重复字母

题目&#xff1a; 题解&#xff1a; class Solution {public String removeDuplicateLetters(String s) {boolean[] vis new boolean[26];int[] num new int[26];for (int i 0; i < s.length(); i) {num[s.charAt(i) - a];}StringBuffer sb new StringBuffer();for (in…...

Taro学习记录

一、安装taro-cli 二、项目文件 三、项目搭建 1、Eslint配置 在项目生成的 .eslintrc 中进行配置 {"extends": ["taro/react"], //一个配置文件&#xff0c;可以被基础配置中的已启用的规则继承"parser": "babel/eslint-parser…...

Spring Cache框架详解

Spring Cache框架详解 Spring Cache是Spring框架提供的一个强大的缓存抽象层&#xff0c;旨在简化缓存技术的集成和使用。自Spring 3.1版本开始&#xff0c;Spring Cache就被引入以支持在Spring应用程序中添加缓存功能。随着Spring版本的迭代&#xff0c;Spring Cache的功能日…...

解决Html iframe 内嵌video标签导致视频无法全屏展示的问题

原因&#xff1a; 由于浏览器的安全策略所限制的。为了防止恶意网站利用全屏播放功能进行滥用或欺骗用户&#xff0c;浏览器对iframe中的视频播放做了限制。 在iframe标签中播放视频时&#xff0c;浏览器会根据安全策略阻止视频全屏播放。这是因为iframe标签中的内容被认为是第…...

谷粒商城实战笔记-110~114-全文检索-ElasticSearch-查询

文章目录 一&#xff0c;110-全文检索-ElasticSearch-进阶-两种查询方式二&#xff0c;111-全文检索-ElasticSearch-进阶-QueryDSL基本使用&match_all三&#xff0c;112-全文检索-ElasticSearch-进阶-match全文检索四&#xff0c;113-全文检索-ElasticSearch-进阶-match_ph…...

【开源】嵌入式Linux(IMX6U)应用层综合项目(1)--云平台调试APP

目录 1.简介 1.1功能介绍 1.2技术栈介绍 1.3演示视频 1.4硬件介绍 2.软件设计 2.1连接阿里云 2.2云平台调试UI 2.3Ui_main.c界面切换处理文件 2.4.main函数 3.结尾&#xff08;附网盘链接&#xff09; 1.简介 此文章并不是教程&#xff0c;只能当作笔者的学习分享&…...

AI人工智能分析王楚钦球拍被踩事件的真相

在2024年巴黎奥运会乒乓球混双决赛的热烈氛围中&#xff0c;中国队王楚钦与孙颖莎以出色的表现夺得金牌&#xff0c;然而&#xff0c;赛后发生的一起意外事件——王楚钦的球拍被踩坏&#xff0c;引起了广泛关注和热议。为了探寻这一事件的真相&#xff0c;我们可以借助AI人工智…...

C++客户端Qt开发——多线程编程(一)

多线程编程&#xff08;一&#xff09; ①QThread 在Qt中&#xff0c;多线程的处理一般是通过QThread类来实现。 QThread代表一个在应用程序中可以独立控制的线程&#xff0c;也可以和进程中的其他线程共享数据。 QThread对象管理程序中的一个控制线程。 run() 线程的入口…...

安装pnpm

安装pnpm&#xff08;Performant npm&#xff09;&#xff0c;即高性能的npm包管理工具&#xff0c;可以通过多种方式进行。以下是详细的安装步骤&#xff1a; 一、通过npm全局安装 打开命令行工具&#xff1a;在你的计算机上打开命令行工具&#xff0c;例如Windows的CMD、Pow…...

CSS平移实现双开门效果

CSS平移实现双开门效果 一共要三张图片&#xff0c;一张作为父级背景&#xff0c;两张为兄弟左右布局 父子结构布局 一张作为父级背景&#xff0c;两张为兄弟左右布局。之后添加鼠标悬停效果&#xff0c;两张子图分别从左右平移 [外链图片转存失败,源站可能有防盗链机制,建议…...

3096. 得到更多分数的最少关卡数目

3096. 得到更多分数的最少关卡数目 题目链接&#xff1a;3096. 得到更多分数的最少关卡数目 代码如下&#xff1a; class Solution { public:int minimumLevels(vector<int>& possible) {int s0;//两个玩家能得到的分数和for(int x:possible){sx0?-1:1;}int t0;/…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

如何在Windows本机安装Python并确保与Python.NET兼容

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...