我们通常会使用工具jstack 去跟踪线程信息,其如何实现使用attach 的方式还是ptrace 的方式,这些可以去参考本人的博客的其他文章。

但这些方式都是外部使用的方式,如何直接使用java代码得到当前进程的线程的信息,方便监控jvm的整个运行状态,就不的不提到了ManagementFactory

通过调用方法

ThreadMXBean tmbean = ManagementFactory.getThreadMXBean();

通过得到 ThreadMXBean 可以得到非常多的thread信息,博客里也主要提到几个重要函数的实现

ThreadMXBean是个接口,主要实现都是在 ThreadImpl.java 里实现。

1. getThreadCount()

在虚拟机里会有ThreadService,里面会有些计数器用于记录总线程数,活着线程数目


  1. PerfCounter* ThreadService::_total_threads_count = NULL;
  2. PerfVariable* ThreadService::_live_threads_count = NULL;
  3. PerfVariable* ThreadService::_peak_threads_count = NULL;
  4. PerfVariable* ThreadService::_daemon_threads_count = NULL;
  5. volatile int ThreadService::_exiting_threads_count = 0;
  6. volatile int ThreadService::_exiting_daemon_threads_count = 0;

当线程创建,消亡都会调用 ThreadService 的方法来对计数器加减,这样就能直接得到线程数目的状态,而不需要去遍历线程链表。

2. getAllThreadIds()

这个实现也比较简单,直接扫描线程列表,就可以得到每个java 的线程id, 在扫描过程中使用了锁,锁住了线程链表。 但因为从native代码到java代码中没有锁结构,得到线程的列表只能表示当时的状态,当得到id的时候并不能保证该线程依然存活。


  1. ThreadsListEnumerator::ThreadsListEnumerator(Thread* cur_thread,
  2. bool include_jvmti_agent_threads,
  3. bool include_jni_attaching_threads) {
  4. assert(cur_thread == Thread::current(), "Check current thread");
  5. int init_size = ThreadService::get_live_thread_count();
  6. _threads_array = new GrowableArray<instanceHandle>(init_size);
  7. MutexLockerEx ml(Threads_lock);
  8. for (JavaThread* jt = Threads::first(); jt != NULL; jt = jt->next()) {
  9. // skips JavaThreads in the process of exiting
  10. // and also skips VM internal JavaThreads
  11. // Threads in _thread_new or _thread_new_trans state are included.
  12. // i.e. threads have been started but not yet running.
  13. if (jt->threadObj() == NULL ||
  14. jt->is_exiting() ||
  15. !java_lang_Thread::is_alive(jt->threadObj()) ||
  16. jt->is_hidden_from_external_view()) {
  17. continue;
  18. }
  19. // skip agent threads
  20. if (!include_jvmti_agent_threads && jt->is_jvmti_agent_thread()) {
  21. continue;
  22. }
  23. // skip jni threads in the process of attaching
  24. if (!include_jni_attaching_threads && jt->is_attaching()) {
  25. continue;
  26. }
  27. instanceHandle h(cur_thread, (instanceOop) jt->threadObj());
  28. _threads_array->append(h);
  29. }
  30. }

我们也可以看到 JNI attach 的线程,和jvmti agent的线程是不被统计在内的

3. ThreadInfo[] getThreadInfo 得到线程具体的堆栈信息

不论是传入要取的线程列表还是要取的所有的线程列表,最后都会看到将取堆栈信息的任务交给了vm thread 线程处理,关于vm thread的作用可以参考本人的其他博客。


  1. // Obtain thread dumps and thread snapshot information
  2. VM_ThreadDump op(dump_result,
  3. thread_handle_array,
  4. num_threads,
  5. max_depth, /* stack depth */
  6. with_locked_monitors,
  7. with_locked_synchronizers);
  8. VMThread::execute(&op);

a.  vm thread 去遍历所有线程的信息,由于是单线程处理,如果线程数量多的话是会影响到性能的,因为在扫描堆栈过程中,是在softpoint的状态。

b. ThreadDumpResult dump_result(num_threads); 使用ThreadDumpResult 去存储ThreadSnapshot 而保证不会被gc,因为从vm thread抓取线程结束,在填充threadinfo的时候还是会发生gc。

4. 锁的细节显示

在函数 dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers)里有2个参数 lockedMonitor, 和 lockedSynchronizer

而这两个参数分别控制两种锁ThreadInfo .getLockedMonitors()  和 ThreadInfo.getLockedSynchronizers()

a.  Monitor 锁

就是我们传统使用的synchronized(Object obj),

可以通过MonitorInfo[]得到具体的锁的数量和信息

b. Locked ownable synchronizers 锁

常指的ReentrantLock 和 ReentrantReadWriteLock 锁

通过得到LockInfo[]  可以得到具体的类,锁的数量和信息

JVM源码系列:ThreadMXBean 打出堆栈信息原理分析的更多相关文章

  1. Mybaits 源码解析 (五)----- 面试源码系列:Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)

    刚开始使用Mybaits的同学有没有这样的疑惑,为什么我们没有编写Mapper的实现类,却能调用Mapper的方法呢?本篇文章我带大家一起来解决这个疑问 上一篇文章我们获取到了DefaultSqlSe ...

  2. Spring源码系列 — 注解原理

    前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...

  3. Spring源码系列 — BeanDefinition

    一.前言 回顾 在Spring源码系列第二篇中介绍了Environment组件,后续又介绍Spring中Resource的抽象,但是对于上下文的启动过程详解并未继续.经过一个星期的准备,梳理了Spri ...

  4. 事件机制-Spring 源码系列(4)

    事件机制-Spring 源码系列(4) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcess ...

  5. Ioc容器BeanPostProcessor-Spring 源码系列(3)

    Ioc容器BeanPostProcessor-Spring 源码系列(3) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Io ...

  6. JVM源码分析之Metaspace解密

        概述 metaspace,顾名思义,元数据空间,专门用来存元数据的,它是jdk8里特有的数据结构用来替代perm,这块空间很有自己的特点,前段时间公司这块的问题太多了,主要是因为升级了中间件所 ...

  7. 9 hbase源码系列(九)StoreFile存储格式

    hbase源码系列(九)StoreFile存储格式    从这一章开始要讲Region Server这块的了,但是在讲Region Server这块之前得讲一下StoreFile,否则后面的不好讲下去 ...

  8. 从jvm源码看synchronized

    从jvm源码看synchronized 索引 synchronized的使用 修饰实例方法 修饰静态方法 修饰代码块 总结 Synchronzied的底层原理 对象头和内置锁(ObjectMonito ...

  9. JVM源码分析-JVM源码编译与调试

    要分析JVM的源码,结合资料直接阅读是一种方式,但是遇到一些想不通的场景,必须要结合调试,查看执行路径以及参数具体的值,才能搞得明白.所以我们先来把JVM的源码进行编译,并能够使用GDB进行调试. 编 ...

随机推荐

  1. 【2017"百度之星"程序设计大赛 - 初赛(B)】Chess

    [链接]http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=776&pid=1001 [题意] 在这里写题意 [题 ...

  2. 洛谷 P1689 方程求解

    P1689 方程求解 题目描述 给一个方程,形如X+Y=Z或X-Y=Z.给出了其中两个未知数,请求出第三个数.未知数用‘?’表示,等式中也许会出现一些多余的空格. 输入输出格式 输入格式: 一行,方程 ...

  3. [CortexM0--stm32f0308]discovery开发板

        问题描写叙述:stm32提供了很多IC入门级开发板,价格还是蛮廉价的. stm32f0308-discovery就是一款cortex-m0架构的入门级开发板. 例如以下对其进行下简介. IO便 ...

  4. 【编程】辨异 —— proxy 与 delegate

    二者分别对应着设计模式中的代理模式和委托模式. proxy:译为代理, 被代理方(B)与代理方(A)的接口完全一致. 主要使用场景(语义)应该是:为简化编程(或无法操作B),不直接把请求交给被代理方( ...

  5. php网页跳转无法获取session值

    今日编写项目,需要在跳转后的页面获取session值进行自动登录操作,但是明明在传输页面可以打印出session值,但在接受页面却显示session值为空,经确认脚本中的session_start() ...

  6. call.apply.冒充对象继承

    call方法:让调用对象执行,然后第一参数是谁.调用对象的this就改变,指向谁,后边跟参数,依次对应传入 apply方法:让调用对象执行,然后第一参数是谁.调用对象的this就改变指向是谁,后边跟参 ...

  7. Surging 微服务框架使用入门

    原文:Surging 微服务框架使用入门 前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正.  我对 surging 的看法 我目前所在的公司采用架构就是类似与Sur ...

  8. 【Struts2三】拦截器

    拦截器:就是在訪问action之前.对其进行拦截!能够在拦截器中做一些逻辑的处理! 比方权限验证.没有权限就不给予訪问! 拦截器等效于servlet中的过滤器! 使用拦截器步骤: 1.定义自己的拦截器 ...

  9. WPF学习笔记——概述

    如果你选择WPF,多半原因是因为折服于它那震撼性的用户体验.纵观WPF整个知识体系,其内容并不复杂,但却比较细碎,不易理清.以下内容是对WPF部分内容的简单概括,希望读者能够对WPF框架有个大体认识. ...

  10. UIDeviceOrientationDidChangeNotification和UIApplicationDidChangeStatusBarFrameNotification

    这几天做App的时候,需要添加旋转屏通知以便调整UI布局 刚开始我使用的是UIDeviceOrientationDidChangeNotification, 一直有一些问题就是,如果使用这个通知,当i ...