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

JVisualVM 中线程状态(运行/休眠/等待/驻留/监视)解析

在java自带的工具JVirtualVM中线程有以下几种状态:

先说结论,各状态含义如下,后面有详细的demo测试验证:

  • 运行(runnable):正在运行中的线程。

  • 休眠(timed_waiting):休眠线程,例如调用Thread.sleep方法。

  • 等待(waiting):等待唤醒的线程,可通过调用Object.wait方法获得这种状态,底层实现是基于对象头中的monitor对象

  • 驻留(waiting):等待唤醒的线程,和等待状态类似,只不过底层的实现方式不同,处于这种状态的例子有线程池中的空闲线程,等待获取reentrantLock锁的线程,调用了reentrantLock的condition的await方法的线程等等,底层实现是基于Unsafe类的park方法,在AQS中有大量的应用。

  • 监视(blocked):等待获取monitor锁的线程,例如等待进入synchronize代码块的线程。

代码测试

    private static final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();    private static final ReentrantLock reentrantLockTest = new ReentrantLock();    public static void main(String[] args) {        //基于println方法中的synchronize代码块测试运行或者监视线程
        Thread thread1 = new Thread(() -> {            while (true) {
                System.out.println("运行或者监视线程1");
            }
        }, "运行或者监视线程1");
        thread1.start();        //基于println方法中的synchronize代码块测试运行或者监视线程
        Thread thread2 = new Thread(() -> {            while (true) {
                System.out.println("运行或者监视线程2");
            }
        }, "运行或者监视线程2");
        thread2.start();        //monitor对象等待线程
        Object lock = new Object();        Thread thread3 = new Thread(() -> {            synchronized (lock) {                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "等待线程synchronized");
        thread3.start();        //reentrantLock中的条件对象调用await方法线程为驻留线程
        ReentrantLock reentrantLock = new ReentrantLock();        Condition condition = reentrantLock.newCondition();        Thread thread4 = new Thread(() -> {
            reentrantLock.lock();            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        }, "等待线程reentrantLock");
        thread4.start();        //休眠线程
        Thread thread5 = new Thread(() -> {            try {
                Thread.sleep(1000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "休眠线程");
        thread5.start();        Thread thread6 = new Thread(ThreadTest::lockMethod, "reentrantLock运行线程");
        thread6.start();        //等待获取reentrantLock的线程为驻留线程
        Thread thread7 = new Thread(() -> {            try {
                TimeUnit.MICROSECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lockMethod();
        }, "reentrantLock监视线程");
        thread7.start();        //线程池中的空闲线程为驻留线程
        singleThreadExecutor.execute(() -> {            //线程池中的线程是懒加载,需要运行任务之后才会产生线程
            System.out.println("驻留线程运行");
        });
    }    private static void lockMethod() {
        reentrantLockTest.lock();        try {            while (true) {
            }
        } finally {
            reentrantLockTest.unlock();
        }
    }	//println源码也简单贴一下
	//java.io.PrintStream#println(java.lang.String)
    public void println(String x) {        //this表示System.out这个PrintStream对象
        synchronized (this) {
            print(x);
            newLine();
        }
    }

以上代码运行之后,打开JVirtualVM查看线程如下:

根据代码的顺序从上至下讲:

  • 两个运行或者监视线程的System.out.println()语句因为抢同一个synchronize锁,可以很明显的看出是在交替运行,状态分别处于运行监视状态。

  • 等待线程synchronize因为调用了Object的wait方法,一直处于等待状态。

  • 休眠线程省略。

  • 重点是和reentrantLock锁相关的三个线程,注意下上图中有一个地方写错了,等待线程reentrantLock,实际应该是驻留线程reentrantLock,可以看到无论是通过condition的await方法,还是在阻塞等待锁的过程中,都是处于驻留状态,而不是我一开始预想的等待状态,通过查看源码后发现它们最终都调用了Unsafe的park方法,后续的线程dump也能验证这一点。

  • pool- 1-threadpool-1就是那个线程池,因为里面的线程处于空闲状态,也属于驻留

线程dump

相关文章:

  • 常识——绳结打折法
  • AVL树的特性和模拟实现
  • java剧院售票系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  • SpringBoot-36-分布式理论概述
  • 第一章 Linux及Linux Shell简介
  • http客户端Feign
  • SpringBoot-37-RPC概述
  • tensorflo之keras高层接口
  • OpenCV图像处理学习二十一,直方图比较方法
  • 第5章 总体设计【软件设计一般分为总体设计和详细设计,它们之间的关系是全局与局部】
  • java开放式教学评价管理系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  • define宏定义和const的区别
  • 电量优化 - Hook 系统服务
  • 网课搜题公众号 接口查题 查课接口 网课题库对接教程 附接口
  • 软件测试基础
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 〔开发系列〕一次关于小程序开发的深度总结
  • Android 控件背景颜色处理
  • crontab执行失败的多种原因
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • ERLANG 网工修炼笔记 ---- UDP
  • If…else
  • JavaScript服务器推送技术之 WebSocket
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 悄悄地说一个bug
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • #预处理和函数的对比以及条件编译
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (30)数组元素和与数字和的绝对差
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (pojstep1.3.1)1017(构造法模拟)
  • (二)c52学习之旅-简单了解单片机
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (算法设计与分析)第一章算法概述-习题
  • (一)认识微服务
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • ./configure,make,make install的作用(转)
  • .dwp和.webpart的区别
  • .NET BackgroundWorker
  • .net反编译工具
  • .NET下ASPX编程的几个小问题
  • .NET运行机制
  • @EnableAsync和@Async开始异步任务支持
  • [Android] Upload package to device fails #2720
  • [BT]小迪安全2023学习笔记(第15天:PHP开发-登录验证)
  • [CSDN首发]鱿鱼游戏的具体玩法详细介绍
  • [LeetCode] Minimum Path Sum
  • [ndss 2023]确保联邦敏感主题分类免受中毒攻击
  • [nlp] 损失缩放(Loss Scaling)loss sacle
  • [node] Node.js的全局对象Global