JVM 内部运行线程介绍


详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp47


最近在找关于JVM内部线程管理的资料,发现网上相关帖子很少,有一些还是胡说的,下面这个文章看起来还是不错的,虽然有一点儿乱,但是也得为作者致敬了。

最近抽时间把JVM运行过程中产生的一些线程进行了整理,主要是围绕着我们系统jstack生成的文件为参照依据。  前段时间因为系统代码问题,造成性能瓶颈,于是就dump了一份stack出来进行分析。stack 里面线程非常多,排查起来需要一定的经验,所以,对它们有一定了解,可以提高排查问题的效率。现在网上资料也不是特别全,所以,导致很多新人在拿到一个stack文件之后,也不知知道从何看起。下面我把这次整理的一些个人认为比较常见的线程列出来。




所属





Attach Listener





          Attach Listener线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。





JVM





CompilerThread0





       用来调用JITing,实时编译装卸class。通常,jvm会启动多个线程来处理这部分工作,线程名称后面的数字也会累加,例如:CompilerThread1





JVM





DestroyJavaVM





执行main()的线程在main执行完后调用JNI中的jni_DestroyJavaVM()方法唤起DestroyJavaVM线程。   JVM在Jboss服务器启动之后,就会唤起DestroyJavaVM线程,处于等待状态,等待其它线程(java线程和native线程)退出时通知它卸载JVM。线程退出时,都会判断自己当前是否是整个JVM中最后一个非deamon线程,如果是,则通知DestroyJavaVM线程卸载JVM。ps:扩展一下:1.如果线程退出时判断自己不为最后一个非deamon线程,那么调用thread->exit(false),并在其中抛出thread_end事件,jvm不退出。2.如果线程退出时判断自己为最后一个非deamon线程,那么调用before_exit()方法,抛出两个事件: 事件1:thread_end线程结束事件、事件2:VM的death事件。然后调用thread->exit(true)方法,接下来把线程从active list卸下,删除线程等等一系列工作执行完成后,则通知正在等待的DestroyJavaVM线程执行卸载JVM操作。







JBOSS





ConfigClientNotifier





         ConfigServer服务端当有配置变更时,就会将最新的配置推送到ConfigServer客户端的一个数据列队中,ConfigClientNotifier线程用于定期检查该数据列队中是否有数据,如果有数据,则将数据分发到订阅该数据的组件去做业务逻辑,比如:tair和hsf的数据都订阅了ConfigServer数据源,当ConfigClientNotifier线程发现数据有更新时,就触发做数据分发特定特定信号标识将数据分发到相应的订阅者。





ConfigServer





Dispatcher-Thread-3





      Log4j具有异步打印日志的功能,需要异步打印日志的Appender都需要注册到AsyncAppender对象里面去,由AsyncAppender进行监听,决定何时触发日志打印操作。AsyncAppender如果监听到它管辖范围内的Appender有打印日志的操作,则给这个Appender生成一个相应的event,并将该event保存在一个buffuer区域内。  Dispatcher-Thread-3线程负责判断这个event缓存区是否已经满了,如果已经满了,则将缓存区内的所有event分发到Appender容器里面去,那些注册上来的Appender收到自己的event后,则开始处理自己的日志打印工作。Dispatcher-Thread-3线程是一个守护线程。





JVM





Gang worker#0





JVM用于做新生代垃圾回收(monir gc)的一个线程。#号后面是线程编号,例如:Gang worker#1





JVM





IdleRemover





Jboss连接池有一个最小值,该线程每过一段时间都会被Jboss唤起,用于检查和销毁连接池中空闲和无效的连接,直到剩余的连接数小于等于它的最小值。





JVM





FelixDispatchQueue





       该线程会在sofa启动时会唤起该线程,该线程用于分发OSGI事件到Declarative Services 中去发布,查找,绑定目标服务。其实,我们接口配置的service和reference就涉及到服务的发布、查找和绑定工作。   Declarative Services 主要工作职责是方便地对服务之间的依赖关系和状态进行监听和管理。OSGI使用事件策略去调用Declarative Services中的服务。







Quartz





InsttoolCacheScheduler_

Worker-2





InsttoolCacheScheduler_Worker-2线程就是ThreadPool线程的一个简单实现,它主要负责分配线程资源去执行InsttoolCacheScheduler_QuartzSchedulerThread线程交给它的调度任务(也就是JobRunShell)。







JVM





JBossLifeThread





        Jboss主线程启动成功,应用程序部署完毕之后将JBossLifeThread线程实例化并且start,JBossLifeThread线程启动成功之后就处于等待状态,以保持Jboss Java进程处于存活中。 所得比较通俗一点,就是Jboss启动流程执行完毕之后,为什么没有结束?就是因为有这个线程hold主了它。牛b吧~~





Jboss





JCA PoolFiller





   该线程主要为JBoss内部提供连接池的托管。 简单介绍一下工作原理 :Jboss内部凡是有远程连接需求的类,都需要实现ManagedConnectionFactory接口,例如需要做JDBC连接的XAManagedConnectionFactory对象,就实现了该接口。然后将XAManagedConnectionFactory对象,还有其它信息一起包装到InternalManagedConnectionPool对象里面,接着将InternalManagedConnectionPool交给PoolFiller对象里面的列队进行管理。   JCA PoolFiller线程会定期判断列队内是否有需要创建和管理的InternalManagedConnectionPool对象,如果有的话,则调用该对象的fillToMin方法,触发它去创建相应的远程连接,并且将这个连接维护到它相应的连接池里面去。





JVM





JDWP TransportListener: dt_socket





该线程是一个Java Debugger的监听器线程,负责受理客户端的debug请求。通常我们习惯将它的监听端口设置为8787。





JVM





process reaper





   该线程负责去执行一个OS命令行的操作。





JVM





SurrogateLockerThread

(CMS)





          这个线程主要用于配合CMS垃圾回收器使用,它是一个守护线程,其主要负责处理GC过程中,Java层的Reference(指软引用、弱引用等等)与jvm内部层面的对象状态同步。这里对它们的实现稍微做一下介绍:这里拿WeakHashMap做例子,将一些关键点先列出来(我们后面会将这些关键点全部串起来):

1.      我们知道HashMap用Entry[]数组来存储数据的,WeakHashMap也不例外,内部有一个Entry[]数组。

3.      Reference里面有一个全局锁对象:Lock,它也被称为pending_lock.   注意:它是静态对象。

5. Reference 里面有一个静态内部类:ReferenceHandler的线程,它在static块里面被初始化并且启动,启动完成后处于wait状态,它在一个Lock同步锁模块中等待。

7.      上面关键点就介绍完毕了,下面我们把他们串起来。



taskObjectTimerFactory





         顾名思义,该线程就是用来执行任务的。当我们把一个任务交给Timer对象,并且告诉它执行时间,周期时间后,Timer就会将该任务放入任务列队,并且通知taskObjectTimerFactory线程去处理任务,taskObjectTimerFactory线程会将状态为取消的任务从任务列队中移除,如果任务是非重复执行类型的,则在执行完该任务后,将它从任务列队中移除,如果该任务是需要重复执行的,则计算出它下一次执行的时间点。





JVM





VM Thread





        这个线程就比较牛b了,是jvm里面的线程母体,根据hotspot源码(vmThread.hpp)里面的注释,它是一个单例的对象(最原始的线程)会产生或触发所有其他的线程,这个单个的VM线程是会被其他线程所使用来做一些VM操作(如,清扫垃圾等)。在 VMThread的结构体里有一个VMOperationQueue列队,所有的VM线程操作(vm_operation)都会被保存到这个列队当中,VMThread本身就是一个线程,它的线程负责执行一个自轮询的loop函数(具体可以参考:VMThread.cpp里面的void VMThread::loop()),该loop函数从VMOperationQueue列队中按照优先级取出当前需要执行的操作对象(VM_Operation),并且调用VM_Operation->evaluate函数去执行该操作类型本身的业务逻辑。ps:VM操作类型被定义在vm_operations.hpp文件内,列举几个:ThreadStop、ThreadDump、PrintThreads、GenCollectFull、GenCollectFullConcurrent、CMS_Initial_Mark、CMS_Final_Remark…..有兴趣的同学,可以自己去查看源文件。



原文地址:https://www.cnblogs.com/grefr/p/5046322.html