Java多线程与JConsole实践:从线程状态到性能优化!!!
目录
- 一、前言
- 二、`JConsole `使用教程
- 二、线程的基本状态
- 2.1新建状态(New)
- 2.2就绪状态(Ready)
- 2.3运行状态(Running)
- 2.4 阻塞状态(Blocked)
- 2.5. 等待状态(Waiting)
- 2.6 等待状态(TIMED_WAITING)
- 2.7终止状态(TERMINATED)
- 二、线程状态的转换
- 三、线程安全与状态管理
- 四、总结
一、前言
在操作系统和并发编程中,线程作为最小的执行单位,其生命周期中会经历多个不同的状态。理解这些状态及其转换非常重要,因为它们直接关系到程序的正确性和性能。本文将详细解析线程的各个状态及其转换关系。
二、JConsole 使用教程
JConsole 是一种 Java 监控和管理控制台工具,可以用于监视 Java 虚拟机(JVM)的性能和资源利用情况。它提供了一种图形化界面,可以实时查看 JVM 的运行状态、内存使用情况、线程活动、垃圾回收等信息,以及执行一些管理操作
1.启动
JConsole
JConsole 是包含在 JDK 中的一个工具,因此首先要确保已经安装了 JDK。然后,找到jconsole.exe的位置然后 双击 jconsole.exe 启动 JConsole。

2.连接到 Java 进程
启动 JConsole 后,会弹出一个界面,显示所有正在运行的 Java 进程。选择要监控的 Java 进程,并点击连接按钮
我们先简单看一个代码:
public class Tsleep {public static void main(String[] args) {Thread t=new Thread(()->{try {Thread.sleep(3000);System.out.println("运行线程...");} catch (InterruptedException e) {e.printStackTrace();}},"T1");t.start();System.out.println("main....线程运行...");}
}
启动项目:然后打开jconsoel选中我们需要观察的线程。

3.本地连接
在本地进程中会展示出当前计算机所有正在运行的 Java 程序,只需选中双击进入,再点击“不安全的连接”即可进入到监听界面


然后我们就可以通过这个jconsole来更好的观察线程状态了。
二、线程的基本状态
2.1新建状态(New)
- 当线程被创建时,线程处于新建状态。
- 此时线程尚未开始执行,只是被操作系统或运行时环境识别为一个线程对象。
- 例如:使用
new Thread()创建一个线程实例,线程处于新建状态。
NEW: 安排了工作, 还未开始行动。
public class Tsleep {public static void main(String[] args) {Thread t=new Thread(()->{try {Thread.sleep(10000);System.out.println("运行线程...");} catch (InterruptedException e) {e.printStackTrace();}},"T1");System.out.println(t.getState());t.start();}
}

线程在start之前的状态。
可以看到NEW状态被打印出来了,这就是新建状态。
2.2就绪状态(Ready)
- 线程被操作系统的调度器识别为可执行状态,等待 CPU 资源。
- 此时线程已经被初始化并且具备了运行条件。
当线程被创建(如 new Thread())后,线程处于 Ready 状态,但尚未开始执行。
例如:
Thread thread = new Thread(() -> {System.out.println("Hello, Thread!");
});
// 此时线程处于 Ready 状态,但尚未调用 start()
2.3运行状态(Running)
线程获得 CPU 时间片,开始执行线程的
run()方法。
这是线程执行任务的核心状态。
RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作
public class Dom12 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{while (true){//这里什么都不做}});t.start();//真正工作的状态System.out.println(t.getState());}
}

Ready 状态与 Running 状态的区别
| 特性 | Ready 状态(就绪状态) | Running 状态(运行状态) |
|---|---|---|
| CPU 资源 | 等待 CPU 资源 | 获得 CPU 资源,正在执行任务 |
| 执行状态 | 未执行 | 执行中 |
| 进入方式 | 调用 start()、从阻塞/等待恢复 | 调度器选择并分配 CPU 时间片 |
| 退出方式 | 获得 CPU 后进入 Running 状态 | 时间片用完或被中断,返回 Ready 状态 |
2.4 阻塞状态(Blocked)
- 线程因等待某些资源(如 I/O、锁等)而暂停执行。
- 阻塞状态的线程不在就绪队列中,直到等待的资源可用才会解除阻塞。
- 例如:线程尝试获取一个已经被其他线程占用的锁时,会进入阻塞状态。
package tset1;public class Tsleep {public static void main(String[] args) throws InterruptedException {// 共享的锁对象Object lock = new Object();
// 线程 1Thread thread1 = new Thread(() -> {synchronized (lock) {System.out.println("Thread1: 已进入同步块");try {for (int i = 0; i < 5; i++) {System.out.println("Thread1: 迭代 " + i);Thread.sleep(3000); // 睡眠3000毫秒}} catch (InterruptedException e) {System.out.println("Thread1: 被中断");}System.out.println("Thread1: 已退出同步块");}},"T1");// 线程 2Thread thread2 = new Thread(() -> {synchronized (lock) {System.out.println("Thread2: 已进入同步块");try {for (int i = 0; i < 5; i++) {System.out.println("Thread2: 迭代 " + i);Thread.sleep(3000); // 睡眠 3000 毫秒}} catch (InterruptedException e) {System.out.println("Thread2: 被中断");}System.out.println("Thread2: 已退出同步块");}},"T2");// 启动两个线程thread1.start();thread2.start();// 主线程等待两个子线程完成try {thread1.join();thread2.join();} catch (InterruptedException e) {System.out.println("Main: 在等待子线程完成时被中断");}}
}
代码解释
共享锁对象:
Object lock = new Object(); 定义了一个共享的锁对象,用于在多个线程之间同步。
线程创建:
创建了两个线程 thread1 和 thread2,它们都将尝试获取锁 lock。
在 synchronized (lock) 块内,线程将执行一个循环,睡眠500毫秒,模拟执行任务。
启动线程:
thread1.start(); 和 thread2.start(); 启动了两个线程,让它们竞争锁 lock。
主线程等待:
thread1.join();和thread2.join(); 确保主线程在等待两个子线程完成后再退出。

2.5. 等待状态(Waiting)
WAITING 状态是无限等待状态,直到被其他线程唤醒。
public class Dom14 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{while (true){//System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new NullPointerException();}}});t.start();//join() 会出现WAITING状态 --死等t.join();System.out.println(t.getState());}
}
通过控制台观察不到,因为出现了死等所以,所以jconsole进行观察:

阻塞状态与等待状态的区别

2.6 等待状态(TIMED_WAITING)
TIMED_WAITING 状态是有限等待状态,线程会在指定时间后自动退出。
public class Dom13 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{while (true){//System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new NullPointerException();}}});t.start();Thread.sleep(100);//指定时间的阻塞 TIMED_WAITING 状态System.out.println(t.getState());//join(时间)也会进入TIMED_WAITING 状态t.join(100);System.out.println(t.getState());}
}

2.7终止状态(TERMINATED)
- 线程完成执行或 debido a una interrupción external، 执行结束。
- 一旦线程终止,其资源会被操作系统回收。
TERMINATED: 工作完成了.
public class Dom11 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{System.out.println("hello thread");});t.start();Thread.sleep(1000);//内核当中的线程已经结束了(工作结束了)System.out.println(t.getState());}
}

二、线程状态的转换
线程状态之间的转换是由操作系统的调度器和线程自身的行为决定的。以下是线程状态转换的常见情况:

⼤家不要被这个状态转移图吓到,我们重点是要理解状态的意义以及各个状态的具体意思。
例子:(银行的例子)
刚把李四、王五找来,还是给他们在安排任务,没让他们行动起来,就是 NEW 状态;
当李四、王五开始去窗口排队,等待服务,就进⼊到 RUNNABLE 状态。该状态并不表示已经被银行工作⼈员开始接待,排在队伍中也是属于该状态,即可被服务的状态,是否开始服务,则看调度器的调度;
当李四、王五因为⼀些事情需要去忙,例如需要填写信息、回家取证件、发呆⼀会等等时,进入BLOCKED 、 WATING 、 TIMED_WAITING 状态;如果李四、王五已经忙完,为 TERMINATED 状态。
- 就绪 → 运行
- 操作系统的调度器选择一个就绪状态的线程,并分配 CPU 时间片。
- 例如:
Thread thread = new Thread(); thread.start();
-
运行 → 就绪
- 线程的 CPU 时间片用完,被调度器剥夺 CPU 使用权。
- 例如:操作系统使用时间片调度,线程的时间片到期后会被暂停。
-
运行 → 阻塞
- 线程在执行过程中等待某些资源(如 I/O 或锁),主动放弃 CPU。
例如:线程尝试获取一个被其他线程占用的锁:
java synchronized (lock) { //如果 lock 已被另一个线程占用,此线程将进入阻塞状态 }
- 运行 → 等待
- 线程主动调用某些方法(如
sleep()),等待特定条件满足。
** 例如:**
java Thread.sleep(1000); //线程进入等待状态,等待 1 秒
- 阻塞/等待 → 就绪
- 阻塞状态的线程等到所需资源可用(如锁被释放)。
- 等待状态的线程等到超时或被其他线程唤醒。
- 例如:
// 阻塞状态的线程获取锁后会自动转移到就绪状态
三、线程安全与状态管理
在多线程编程中,线程状态的管理直接关系到程序的正确性和性能。以下是需要注意的事项:
- 避免长时间占用 CPU
- 长时间占用 CPU 的线程会导致其他线程饥饿。
- 建议使用
yield()或sleep()方法让出 CPU。
- 合理加锁和解锁
- 锁的不当使用可能导致线程长时间阻塞。
- 例如:在持有锁时避免执行耗时操作。
- 正确使用等待/通知机制
- 使用
wait()和notify()方法可以更高效地管理线程间的协作。- 例如:实现生产者-消费者模式时,使用等待队列管理线程状态。
四、总结
在本文中,我们将通过JConsole这款强大的工具,深入探索Java多线程的核心知识。从线程的基本状态(如新建、就绪、运行、阻塞、等待和终止)到线程状态之间的转换机制,帮助开发者更好地理解和管理线程。通过实践性的教程,读者将学会如何利用JConsole监控和调试线程,从而优化应用程序的性能和稳定性。这篇文章适合Java开发人员和对并发编程感兴趣的学习者,旨在提供一份清晰易懂的指南,助力在多线程编程中游刃有余
如果您需要更深入的内容或具体案例,可以在留言区告诉我!
相关文章:
Java多线程与JConsole实践:从线程状态到性能优化!!!
目录 一、前言二、JConsole 使用教程二、线程的基本状态2.1新建状态(New)2.2就绪状态(Ready)2.3运行状态(Running)2.4 阻塞状态(Blocked)2.5. 等待状态(Waitingÿ…...
从入门到精通:SQL注入防御与攻防实战——红队如何突破,蓝队如何应对!
引言:为什么SQL注入攻击依然如此强大? SQL注入(SQL Injection)是最古老且最常见的Web应用漏洞之一。尽管很多公司和组织都已经采取了WAF、防火墙、数据库隔离等防护措施,但SQL注入依然在许多情况下能够突破防线&#…...
Stable Diffusion vue本地api接口对接,模型切换, ai功能集成开源项目 ollama-chat-ui-vue
1.开启Stable Diffusion的api服务 编辑webui-user.bat 添加 –api 开启api服务,然后保存启动就可以了 2.api 文档地址 http://127.0.0.1:7860/docs3. 文生图 接口 地址 /sdapi/v1/txt2img //post 请求入参 {enable_hr: false, // 开启高清hrdenoising_stre…...
缓存使用纪要
一、本地缓存:Caffeine 1、简介 Caffeine是一种高性能、高命中率、内存占用低的本地缓存库,简单来说它是 Guava Cache 的优化加强版,是当下最流行、最佳(最优)缓存框架。 Spring5 即将放弃掉 Guava Cache 作为缓存机…...
第十四届蓝桥杯真题(PWM输出)
一.LED 先配置LED的八个引脚为GPIO_OutPut,锁存器PD2也是,然后都设置为起始高电平,生成代码时还要去解决引脚冲突问题 二.按键 按键配置,由原理图按键所对引脚要GPIO_Input 生成代码,在文件夹中添加code文件夹&#…...
【Qt】ffmpeg编码—存储(H264)
目录 一、编码分析 1.解码线程: 编辑2.编码线程: 编辑 编辑 二、ffmpeg编码 1.注册所有组件 2.编码初始化函数 (2)打开视频流 4.查找编码器 5. 写文件头信息,写到formatContex中 6.发送一帧数据给编码器…...
Webview详解(下)
第三阶段:性能优化 加载速度优化 缓存策略 缓存策略可以显著减少网络请求,提升页面加载速度。常用的缓存策略包括 HTTP 缓存和本地资源预加载。 1. HTTP 缓存 HTTP 缓存利用 HTTP 协议中的缓存机制(如 Cache-Control、ETag 等࿰…...
【MySQL基础-16】MySQL DELETE语句:深入理解与应用实践
1. DELETE语句基础:数据删除的艺术 在数据库管理中,DELETE语句是维护数据完整性和清理过期信息的关键工具。与日常生活中的"删除"不同,数据库中的删除操作需要更加谨慎和精确,因为数据一旦删除,恢复可能非常…...
相对位置嵌入和旋转位置编码
1. 相对位置嵌入:给注意力机制加“人际关系记忆” 像班级座位表 想象全班同学(序列的各个元素)坐成一个圈,老师(模型)要记住每个人之间的相对位置: 传统方法:老师给每个座位贴绝对…...
Unity编辑器功能及拓展(1) —特殊的Editor文件夹
Unity中的Editor文件夹是一个具有特殊用途的目录,主要用于存放与编辑器扩展功能相关的脚本和资源。 一.纠缠不清的UnityEditor 我们Unity中进行游戏构建时,我们经常遇到关于UnityEditor相关命名空间丢失的报错,这时候,只得将报错…...
REC一些操作解法
一.Linux命令长度突破 1.源码如下 <?php $param $_REQUEST[param];if ( strlen($param) < 8 ) {echo shell_exec($param); } 2.源码分析 echo执行函数,$_REQUEST可以接post、get、cookie传参 3.破题思路 源码中对参数长度做了限制,小于8位&a…...
powershell7.5.0不支持conda的问题
经历:这周手欠使用vscode的powershell时提示我更新,我就更新了,更新完激活不了conda环境了,查询了半天是powershell最新版7.5.0与目前conda25.1.1以前的版本不支持的问题。 问题环境:powershell版本>7.5.0ÿ…...
Android Jetpack学习总结(源码级理解)
ViewModel 和 LiveData 是 Android Jetpack 组件库中的两个核心组件,它们能帮助开发者更有效地管理 UI 相关的数据,并且能够在配置变更(如屏幕旋转)时保存和恢复 UI 数据。 ViewModel作用 瞬态数据丢失的恢复,比如横竖…...
Unity中UDP异步通信常用API使用
Begin开头的方法 BeginSendTo BeginSendTo 是 UdpClient 类中的一个重要方法,用于开始一个异步操作来发送 UDP 数据报到指定的远程端点 public IAsyncResult BeginSendTo(byte[] datagram,int bytes,IPEndPoint endPoint,AsyncCallback requestCallback,object s…...
解决Dify:failed to init dify plugin db问题
Dify最新版本1.1.3(langgenius/dify: Dify is an open-source LLM app development platform. Difys intuitive interface combines AI workflow, RAG pipeline, agent capabilities, model management, observability features and more, letting you quickly go from prototy…...
[AI绘图] ComfyUI 中自定义节点插件安装方法
ComfyUI 是一个强大的 AI 图像生成工具,支持自定义节点插件扩展其功能。本文介绍 ComfyUI 中安装自定义节点插件的三种方法,包括 Git Clone 方式、插件管理器安装方式,以及手动解压 ZIP 文件的方法,并分析它们的优缺点。 1. Git Clone 方法 使用 git clone 是最稳定且推荐…...
【机械视觉】C#+VisionPro联合编程———【六、visionPro连接工业相机设备】
【机械视觉】C#VisionPro联合编程———【六、visionPro连接工业相机设备】 目录 【机械视觉】C#VisionPro联合编程———【六、visionPro连接工业相机设备】 前言: 连接步骤说明 一. 硬件连接 支持的相机接口类型: 连接步骤 2. 软件配置 Visio…...
CI/CD基础知识
什么是CI/CD CI:持续集成,开发人员频繁地将代码集成到主干(主分支)中每次集成都通过自动化构建和测试来验证,从而尽早发现集成错误,常用的CI工具包括Jenkins、Travis CI、CircleCI、GitLab CI等 CD&#…...
蓝桥杯 之 图论基础+并查集
文章目录 习题联盟X蓝桥幼儿园 图论基础 并查集 并查集,总的来说,操作分为三步初始化(每一个节点的父亲是自己),定义union(index1,index2)函数,定义find(index)函数 并查集详细内容博客 习题 联盟X 联盟X 典型的求解连通分支…...
C# .net ai Agent AI视觉应用 写代码 改作业 识别屏幕 标注等
C# net deepseek RAG AI开发 全流程 介绍_c# 向量处理 deepseek-CSDN博客 视觉多模态大模型 通义千问2.5-VL-72B AI大模型能看懂图 看懂了后能干啥呢 如看懂图 让Agent 写代码 ,改作业,识别屏幕 标注等等。。。 据说是目前最好的免费图片识别框架 通…...
不使用自动映射驼峰命名法,直接在接口上使用注解@Results方法映射
3. 使用注解方式配置 在接口方法上使用 Results 注解: java 复制 Select("SELECT user_name, create_time FROM user WHERE id #{id}") Results({Result(column "user_name", property "userName"),Result(column "crea…...
15届蓝桥JavaB组 前6道题解
15届蓝桥JavaB组 前6道题解 报数游戏类斐波那契循环数分布式队列食堂最优分组星际旅行 报数游戏 import java.util.Scanner;//分析: //20和24的最小公倍数是120 //题目给出了前10个数,发现第10个数是120,说明每10个数出现一个公倍数 //第20个…...
蓝桥杯 14 天 十五届蓝桥杯 数字诗意
static boolean kkk(long x) {if(x1)return true;else {// 初始化xx为1,用于计算2的幂long xx 1;// 循环60次,检查2的幂是否等于xfor (int i 1; i < 60; i) {xx * 2; // 每次将xx乘以2if (xx x) { // 如果xx等于x,说明x是2的幂…...
MP4音视频格式
1.MP4 MP4是一种用于封装音视频/字幕/图片/章节信息等数据的多媒体容器格式,是MPEG-4系列的成员之一 2.文件结构 MP4由一层层的嵌套Box(atom)组成 [ size (4 bytes) ][ type (4 bytes)][ payload (嵌套box或者数据) ] 3.常见Box 类型名称…...
国内GitHub镜像源全解析:加速访问与替代方案指南
在数字化开发日益普及的今天,GitHub作为全球最大的代码托管平台,已成为开发者不可或缺的资源库。然而,由于网络环境的限制,国内用户在访问GitHub时常常面临速度慢、连接不稳定等问题。为了提升开发效率,国内涌现出多个GitHub镜像源,为开发者提供了快速、稳定的代码克隆与…...
CentOS 7 挂载与卸载文件系统笔记
挂载文件系统 挂载的基本概念 挂载是将存储设备(如硬盘分区、U 盘、光盘等)连接到 Linux 文件系统的特定目录(挂载点),使得系统能够访问存储设备上的数据。 查看已挂载的文件系统 命令:mount 或 df -h mo…...
责任链模式-java
1、spring依赖注入模式 @Configuration public class ChainConfig {@Beanpublic ChainSpringFactory chainSpringFactory(List<IHandler<DemoOne,Boolean>> handlerList){return new ChainSpringFactory(handlerList);}} public class DemoOne { }public abstract…...
Vue3动态加载组件,警告:Vue received a Component than was made a reactive object
场景 2个按钮,点击之后,下面加载不同的组件。 现象 分析 实际动态加载的组件,不是深层响应式的,推荐使用 shallowReactive 或 shallowRef,即浅层作用形式,仅最外层是响应式,以此来提升性能。…...
【源码阅读/Vue Flask前后端】简历数据查询功能
目录 一、Flask后端部分modelServiceroute 二、Vue前端部分index.js main.vue功能界面templatescriptstyle 一般就是三个层面,model层面用来建立数据库的字段,service用来对model进行操作,写一些数据库操作的代码,route就是具体的…...
Vue背景介绍+声明式渲染+数据响应式
一、Vue背景 1. 为什么学Vue 1.前后端开发就业必备技能 2.岗位多,绝⼤互联⽹公司都在使⽤Vue,还可以助⼒SpringBoot、C等项⽬开发 3.提⾼开发效率 更少的时间,干更多的活,提高项目开发速度 原生JS做法 Vue做法 总而言之: 使用Vue能够赋能、提升就业竞争…...
