Java多线程与JConsole实践:从线程状态到性能优化!!!

news2025/4/3 2:26:25

目录

  • 一、前言
  • 二、`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();
// 线程 1
        Thread 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");

// 线程 2
        Thread 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 状态。


  1. 就绪 → 运行
  • 操作系统的调度器选择一个就绪状态的线程,并分配 CPU 时间片。
  • 例如
    Thread thread = new Thread();
    thread.start();   
    
  1. 运行 → 就绪

    • 线程的 CPU 时间片用完,被调度器剥夺 CPU 使用权。

    - 例如:操作系统使用时间片调度,线程的时间片到期后会被暂停。

  2. 运行 → 阻塞

  • 线程在执行过程中等待某些资源(如 I/O 或锁),主动放弃 CPU。

例如:线程尝试获取一个被其他线程占用的锁:
java synchronized (lock) { //如果 lock 已被另一个线程占用,此线程将进入阻塞状态 }

  1. 运行 → 等待
  • 线程主动调用某些方法(如 sleep()),等待特定条件满足。

** 例如:**
java Thread.sleep(1000); //线程进入等待状态,等待 1 秒

  1. 阻塞/等待 → 就绪
  • 阻塞状态的线程等到所需资源可用(如锁被释放)。
  • 等待状态的线程等到超时或被其他线程唤醒。
  • 例如:
    // 阻塞状态的线程获取锁后会自动转移到就绪状态
    

三、线程安全与状态管理

在多线程编程中,线程状态的管理直接关系到程序的正确性和性能。以下是需要注意的事项:

  1. 避免长时间占用 CPU
  • 长时间占用 CPU 的线程会导致其他线程饥饿。
  • 建议使用 yield()sleep() 方法让出 CPU。
  1. 合理加锁和解锁
  • 锁的不当使用可能导致线程长时间阻塞。
  • 例如:在持有锁时避免执行耗时操作。
  1. 正确使用等待/通知机制
  • 使用 wait()notify() 方法可以更高效地管理线程间的协作。
  • 例如:实现生产者-消费者模式时,使用等待队列管理线程状态。

四、总结

在本文中,我们将通过JConsole这款强大的工具,深入探索Java多线程的核心知识。从线程的基本状态(如新建、就绪、运行、阻塞、等待和终止)到线程状态之间的转换机制,帮助开发者更好地理解和管理线程。通过实践性的教程,读者将学会如何利用JConsole监控和调试线程,从而优化应用程序的性能和稳定性。这篇文章适合Java开发人员和对并发编程感兴趣的学习者,旨在提供一份清晰易懂的指南,助力在多线程编程中游刃有余

如果您需要更深入的内容或具体案例,可以在留言区告诉我!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Stable Diffusion vue本地api接口对接,模型切换, ai功能集成开源项目 ollama-chat-ui-vue

1.开启Stable Diffusion的api服务 编辑webui-user.bat 添加 –api 开启api服务&#xff0c;然后保存启动就可以了 2.api 文档地址 http://127.0.0.1:7860/docs3. 文生图 接口 地址 /sdapi/v1/txt2img //post 请求入参 {enable_hr: false, // 开启高清hrdenoising_stre…

第十四届蓝桥杯真题(PWM输出)

一.LED 先配置LED的八个引脚为GPIO_OutPut&#xff0c;锁存器PD2也是&#xff0c;然后都设置为起始高电平&#xff0c;生成代码时还要去解决引脚冲突问题 二.按键 按键配置&#xff0c;由原理图按键所对引脚要GPIO_Input 生成代码&#xff0c;在文件夹中添加code文件夹&#…

【Qt】ffmpeg编码—存储(H264)

目录 一、编码分析 1.解码线程&#xff1a; ​编辑2.编码线程&#xff1a; ​编辑 ​编辑 二、ffmpeg编码 1.注册所有组件 2.编码初始化函数 &#xff08;2&#xff09;打开视频流 4.查找编码器 5. 写文件头信息&#xff0c;写到formatContex中 6.发送一帧数据给编码器…

Unity编辑器功能及拓展(1) —特殊的Editor文件夹

Unity中的Editor文件夹是一个具有特殊用途的目录&#xff0c;主要用于存放与编辑器扩展功能相关的脚本和资源。 一.纠缠不清的UnityEditor 我们Unity中进行游戏构建时&#xff0c;我们经常遇到关于UnityEditor相关命名空间丢失的报错&#xff0c;这时候&#xff0c;只得将报错…

REC一些操作解法

一.Linux命令长度突破 1.源码如下 <?php $param $_REQUEST[param];if ( strlen($param) < 8 ) {echo shell_exec($param); } 2.源码分析 echo执行函数&#xff0c;$_REQUEST可以接post、get、cookie传参 3.破题思路 源码中对参数长度做了限制&#xff0c;小于8位&a…

[AI绘图] ComfyUI 中自定义节点插件安装方法

ComfyUI 是一个强大的 AI 图像生成工具,支持自定义节点插件扩展其功能。本文介绍 ComfyUI 中安装自定义节点插件的三种方法,包括 Git Clone 方式、插件管理器安装方式,以及手动解压 ZIP 文件的方法,并分析它们的优缺点。 1. Git Clone 方法 使用 git clone 是最稳定且推荐…

【机械视觉】C#+VisionPro联合编程———【六、visionPro连接工业相机设备】

【机械视觉】C#VisionPro联合编程———【六、visionPro连接工业相机设备】 目录 【机械视觉】C#VisionPro联合编程———【六、visionPro连接工业相机设备】 前言&#xff1a; 连接步骤说明 一. 硬件连接 支持的相机接口类型&#xff1a; 连接步骤 2. 软件配置 Visio…

蓝桥杯 之 图论基础+并查集

文章目录 习题联盟X蓝桥幼儿园 图论基础 并查集 并查集&#xff0c;总的来说&#xff0c;操作分为三步初始化(每一个节点的父亲是自己)&#xff0c;定义union(index1,index2)函数&#xff0c;定义find(index)函数 并查集详细内容博客 习题 联盟X 联盟X 典型的求解连通分支…

C# .net ai Agent AI视觉应用 写代码 改作业 识别屏幕 标注等

C# net deepseek RAG AI开发 全流程 介绍_c# 向量处理 deepseek-CSDN博客 视觉多模态大模型 通义千问2.5-VL-72B AI大模型能看懂图 看懂了后能干啥呢 如看懂图 让Agent 写代码 &#xff0c;改作业&#xff0c;识别屏幕 标注等等。。。 据说是目前最好的免费图片识别框架 通…

15届蓝桥JavaB组 前6道题解

15届蓝桥JavaB组 前6道题解 报数游戏类斐波那契循环数分布式队列食堂最优分组星际旅行 报数游戏 import java.util.Scanner;//分析&#xff1a; //20和24的最小公倍数是120 //题目给出了前10个数&#xff0c;发现第10个数是120&#xff0c;说明每10个数出现一个公倍数 //第20个…

蓝桥杯 14 天 十五届蓝桥杯 数字诗意

static boolean kkk(long x) {if(x1)return true;else {// 初始化xx为1&#xff0c;用于计算2的幂long xx 1;// 循环60次&#xff0c;检查2的幂是否等于xfor (int i 1; i < 60; i) {xx * 2; // 每次将xx乘以2if (xx x) { // 如果xx等于x&#xff0c;说明x是2的幂&#xf…

MP4音视频格式

1.MP4 MP4是一种用于封装音视频/字幕/图片/章节信息等数据的多媒体容器格式&#xff0c;是MPEG-4系列的成员之一 2.文件结构 MP4由一层层的嵌套Box&#xff08;atom&#xff09;组成 [ size (4 bytes) ][ type (4 bytes)][ payload (嵌套box或者数据) ] 3.常见Box 类型名称…

国内GitHub镜像源全解析:加速访问与替代方案指南

在数字化开发日益普及的今天,GitHub作为全球最大的代码托管平台,已成为开发者不可或缺的资源库。然而,由于网络环境的限制,国内用户在访问GitHub时常常面临速度慢、连接不稳定等问题。为了提升开发效率,国内涌现出多个GitHub镜像源,为开发者提供了快速、稳定的代码克隆与…

Vue3动态加载组件,警告:Vue received a Component than was made a reactive object

场景 2个按钮&#xff0c;点击之后&#xff0c;下面加载不同的组件。 现象 分析 实际动态加载的组件&#xff0c;不是深层响应式的&#xff0c;推荐使用 shallowReactive 或 shallowRef&#xff0c;即浅层作用形式&#xff0c;仅最外层是响应式&#xff0c;以此来提升性能。…

【源码阅读/Vue Flask前后端】简历数据查询功能

目录 一、Flask后端部分modelServiceroute 二、Vue前端部分index.js main.vue功能界面templatescriptstyle 一般就是三个层面&#xff0c;model层面用来建立数据库的字段&#xff0c;service用来对model进行操作&#xff0c;写一些数据库操作的代码&#xff0c;route就是具体的…

Vue背景介绍+声明式渲染+数据响应式

一、Vue背景 1. 为什么学Vue 1.前后端开发就业必备技能 2.岗位多&#xff0c;绝⼤互联⽹公司都在使⽤Vue&#xff0c;还可以助⼒SpringBoot、C等项⽬开发 3.提⾼开发效率 更少的时间,干更多的活,提高项目开发速度 原生JS做法 Vue做法 总而言之: 使用Vue能够赋能、提升就业竞争…

HarmonyOS NEXT 鸿蒙中手写和使用第三方仓库封装Logger打印工具

应用场景 在鸿蒙开发中&#xff0c;我们在很多时候调试代码都需要用到日志打印工具&#xff0c;但无论是hilog还是console.log,都用起来相对麻烦&#xff0c;而且需要手动将对象转换为JSON字符串的方式才能打印&#xff0c;并且在控制台日志中输出的格式也非常丑。所以下面我们…

批量合并 PDF 文档,支持合并成单个文档,也支持按文件夹合并 PDF 文档

在日常工作中&#xff0c;合并多个 PDF 文档为一个文件是非常常见的需求。通过合并 PDF&#xff0c;不仅能够更方便地进行管理&#xff0c;还能在特定场景下&#xff08;如批量打印&#xff09;提高效率。那么&#xff0c;当我们需要批量合并多个 PDF 文件时&#xff0c;是否有…

rbpf虚拟机-汇编和反汇编器

文章目录 一、概述二、主要功能三、关键函数解析3.1 汇编器3.1.1 parse -转换为Instruction列表3.1.2 assemble_internal-转换为Insn 3.2 反汇编器3.2.1 to_insn_vec-转换为机器指令 四、总结 Welcome to Code Blocks blog 本篇文章主要介绍了 [rbpf虚拟机-汇编和反汇编器] ❤…

虚拟现实--->unity学习

前言&#xff1a;这学期劳动课选了虚拟现实&#xff0c;其中老师算挺认真的&#xff0c;当然对一些不感兴趣的同学来说是一种折磨&#xff0c;我对这个unity的学习以及后续的虚幻引擎刚开始连基础的概念都没有&#xff0c;后面渐渐也是滋生了一些兴趣&#xff0c;用这篇博客记录…