【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题去除重复字母
题目: 题解: 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"], //一个配置文件,可以被基础配置中的已启用的规则继承"parser": "babel/eslint-parser…...
Spring Cache框架详解
Spring Cache框架详解 Spring Cache是Spring框架提供的一个强大的缓存抽象层,旨在简化缓存技术的集成和使用。自Spring 3.1版本开始,Spring Cache就被引入以支持在Spring应用程序中添加缓存功能。随着Spring版本的迭代,Spring Cache的功能日…...
解决Html iframe 内嵌video标签导致视频无法全屏展示的问题
原因: 由于浏览器的安全策略所限制的。为了防止恶意网站利用全屏播放功能进行滥用或欺骗用户,浏览器对iframe中的视频播放做了限制。 在iframe标签中播放视频时,浏览器会根据安全策略阻止视频全屏播放。这是因为iframe标签中的内容被认为是第…...

谷粒商城实战笔记-110~114-全文检索-ElasticSearch-查询
文章目录 一,110-全文检索-ElasticSearch-进阶-两种查询方式二,111-全文检索-ElasticSearch-进阶-QueryDSL基本使用&match_all三,112-全文检索-ElasticSearch-进阶-match全文检索四,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.结尾(附网盘链接) 1.简介 此文章并不是教程,只能当作笔者的学习分享&…...
AI人工智能分析王楚钦球拍被踩事件的真相
在2024年巴黎奥运会乒乓球混双决赛的热烈氛围中,中国队王楚钦与孙颖莎以出色的表现夺得金牌,然而,赛后发生的一起意外事件——王楚钦的球拍被踩坏,引起了广泛关注和热议。为了探寻这一事件的真相,我们可以借助AI人工智…...

C++客户端Qt开发——多线程编程(一)
多线程编程(一) ①QThread 在Qt中,多线程的处理一般是通过QThread类来实现。 QThread代表一个在应用程序中可以独立控制的线程,也可以和进程中的其他线程共享数据。 QThread对象管理程序中的一个控制线程。 run() 线程的入口…...
安装pnpm
安装pnpm(Performant npm),即高性能的npm包管理工具,可以通过多种方式进行。以下是详细的安装步骤: 一、通过npm全局安装 打开命令行工具:在你的计算机上打开命令行工具,例如Windows的CMD、Pow…...
CSS平移实现双开门效果
CSS平移实现双开门效果 一共要三张图片,一张作为父级背景,两张为兄弟左右布局 父子结构布局 一张作为父级背景,两张为兄弟左右布局。之后添加鼠标悬停效果,两张子图分别从左右平移 [外链图片转存失败,源站可能有防盗链机制,建议…...
3096. 得到更多分数的最少关卡数目
3096. 得到更多分数的最少关卡数目 题目链接:3096. 得到更多分数的最少关卡数目 代码如下: class Solution { public:int minimumLevels(vector<int>& possible) {int s0;//两个玩家能得到的分数和for(int x:possible){sx0?-1:1;}int t0;/…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...