聊聊JVM(五)从JVM角度理解线程

这篇说说如何从JVM的角度来理解线程,可以对Java的线程模型有一个更加深入的理解,对GC的一些细节也会理解地更加深刻。本文基于HotSpot的OpenJDK7实现。

我们知道JVM主要是用C++实现的,JVM定义的Thread的类继承结构如下:

Class hierarchy

- Thread

- NamedThread

- VMThread

- ConcurrentGCThread

- WorkerThread

- GangWorker

- GCTaskThread

- JavaThread

- WatcherThread

另外还有一个重要的类OSThread不在这个继承关系里,它以组合的方式被Thread类所使用

这些类构成了JVM的线程模型,其中最主要的是下面几个类:

java.lang.Thread: 这个是Java语言里的线程类,由这个Java类创建的instance都会 1:1 映射到一个操作系统的osthread

JavaThread: JVM中C++定义的类,一个JavaThread的instance代表了在JVM中的java.lang.Thread的instance, 它维护了线程的状态,并且维护一个指针指向java.lang.Thread创建的对象(oop)。它同时还维护了一个指针指向对应的OSThread,来获取底层操作系统创建的osthread的状态

OSThread: JVM中C++定义的类,代表了JVM中对底层操作系统的osthread的抽象,它维护着实际操作系统创建的线程句柄handle,可以获取底层osthread的状态

VMThread: JVM中C++定义的类,这个类和用户创建的线程无关,是JVM本身用来进行虚拟机操作的线程,比如GC。

有两种方式可以让用户在JVM中创建线程

1. new java.lang.Thread().start()

2. 使用JNI将一个native thread attach到JVM中

针对 new java.lang.Thread().start()这种方式,只有调用start()方法的时候,才会真正的在JVM中去创建线程,主要的生命周期步骤有:

1. 创建对应的JavaThread的instance

2. 创建对应的OSThread的instance

3. 创建实际的底层操作系统的native thread

4. 准备相应的JVM状态,比如ThreadLocal存储空间分配等

5. 底层的native thread开始运行,调用java.lang.Thread生成的Object的run()方法

6. 当java.lang.Thread生成的Object的run()方法执行完毕返回后,或者抛出异常终止后,终止native thread

7. 释放JVM相关的thread的资源,清除对应的JavaThread和OSThread

针对JNI将一个native thread attach到JVM中,主要的步骤有:

1. 通过JNI call AttachCurrentThread申请连接到执行的JVM实例

2. JVM创建相应的JavaThread和OSThread对象

3. 创建相应的java.lang.Thread的对象

4. 一旦java.lang.Thread的Object创建之后,JNI就可以调用Java代码了

5. 当通过JNI call DetachCurrentThread之后,JNI就从JVM实例中断开连接

6. JVM清除相应的JavaThread, OSThread, java.lang.Thread对象

从JVM的角度来看待线程状态的状态有以下几种:

其中主要的状态是这5种:

_thread_new: 新创建的线程

_thread_in_Java: 在运行Java代码

_thread_in_vm: 在运行JVM本身的代码

_thread_in_native: 在运行native代码

_thread_blocked: 线程被阻塞了,包括等待一个锁,等待一个条件,sleep,执行一个阻塞的IO等

从OSThread的角度,JVM还定义了一些线程状态给外部使用,比如用jstack输出的线程堆栈信息中线程的状态:

比较常见有:

Runnable: 可以运行或者正在运行的

MONITOR_WAIT: 等待锁

OBJECT_WAIT: 执行了Object.wait()之后在条件队列中等待的

SLEEPING: 执行了Thread.sleep()的

从JavaThread的角度,JVM定义了一些针对Java Thread对象的状态,基本类似,多了一个TIMED_WAITING的状态,用来表示定时阻塞的状态

最后来看一下JVM内部的VM Threads,主要由几类:

VMThread: 执行JVM本身的操作

Periodic task thread: JVM内部执行定时任务的线程

GC threads: GC相关的线程,比如单线程/多线程的GC收集器使用的线程

Compiler threads: JIT用来动态编译的线程

Signal dispatcher thread: Java解释器Interceptor用来辅助safepoint操作的线程

具体的VMThread的作用,会在讲safepoint的时候细说,就写到这里吧

参考:  Hotspot JVM thread management

时间: 2024-08-10 09:06:37

聊聊JVM(五)从JVM角度理解线程的相关文章

《深入理解Java虚拟机》(五)JVM调优 - 工具

JVM调优 - 工具 JConsole:Java监视与管理控制台 JConsole是一个机遇JMX(Java Management Extensions,即Java管理扩展)的JVM监控与管理工具,监控主要体现在:堆栈内存.线程.CPU.类.VM信息这几个方面,而管理主要是对JMX MBean(managed beans,被管理的beans,是一系列资源,包含对象.接口.设备等)的管理,不仅能查看bean的属性和方法信息,还能够在运行时修改属性或调用方法. 直接在jdk/bin目录下点击jcon

JVM日志和参数的理解

jvm日志和参数 一:理解GC日志格式,读GC日志的方法 1:开启日志 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/gc.log -XX:+UseGCLogFileRotation  启用GC日志文件的自动转储 (Since Java) -XX:NumberOfGClogFiles=1  GC日志文件的循环数目 (Since Java) -XX:GCLogFileSize=1M  控制GC日志文件的大小

jvm内存管理的深入理解以及pc寄存器

 每个Java开发者都知道Java字节码是执行在JRE((Java Runtime Environment Java运行时环境)上的.JRE中最重要的部分是Java虚拟机(JVM),JVM负责分析和执行Java字节码.Java开发人员并不需要去关心JVM是如何运行的.在没有深入理解JVM的情况下,许多开发者已经开发出了非常多的优秀的应用以及Java类库.不过,如果你了解JVM的话,你会更加了解Java的,并且你会轻松解决那些看似简单但是无从下手的问题. 因此,在这篇文件里,我会阐述JVM是如

Jvm(30),理解升级----Java中堆内存和栈内存详解

java中内存分配策略及堆和栈的比较 1 内存分配策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式 的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构 (比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求. 栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分

JVM最多能创建多少个线程: unable to create new native thread

最近需要测试一个长连接服务器,数据上需要达到100W的长连接,测试的客户端,一个线程保持一个连接,发现linux服务器默认创建到3200多个线程的时候,就会报错这个错误"java.lang.OutOfMemoryError: unable to create new native thread.而且,此时整个系统都不能创新新的线程了,不能连接终端,不能执行任何命令. 貌似是内存不足,但实际内存尚有富余,经验证,是linux的一些内核参数限制了创建新的线程. 因为要保持长连接,所有先修改客户端保证

【JVM虚拟机】(6)---深入理解Class中访问标志、类索引、父类索引、接口索引

JVM(6)访问标志,类索引 上一篇博客讲[JVM虚拟机](5)---深入理解JVM-Class中常量池 我们知道一个class文件正常可以分为7个部分: 魔数与class文件版本 常量池 访问标志 类索引.父类索引.接口索引 字段表集合 方法表集合 属性表集合 那么这篇博客主要讲有关 访问标志 和 类索引.父类索引.接口索引 相关的理解和代码示例. 先通俗的说下这两个的作用: 访问标志: 告知该类是一个什么类型的类,是普通类?还是接口?还是枚举?或者其它类,是用什么修饰符修饰该类的. 类索引.

【JVM虚拟机】(7)---深入理解Class中-属性集合

#[JVM虚拟机](7)---深入理解Class中-属性集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机](6)---深入理解Class中访问标志.类索引.父类索引.接口索引 那么这篇博客主要讲有关 字段表集合 相关的理解和代码示例. 字段表:用于描述接口或者类中声明的变量,字段包括类级(static修饰)变量以及实例级变量,但是不包括局部变量(方法内部变量). 一.概念 字段表集合:包括了字段计数器和字段数据

【JVM虚拟机】(8)--深入理解Class中--方法、属性表集合

#[JVM虚拟机](8)--深入理解Class中--方法.属性表集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机](6)---深入理解Class中访问标志.类索引.父类索引.接口索引 3.[JVM虚拟机](7)---深入理解Class中-属性集合 那么这篇博客主要讲有关 方法表集合 相关的理解和代码示例. 方法表集合: 告知该方法是什么修饰符修饰?是否有方法值?返回类型是什么?方法名称,方法参数,还有就是方法内

jvm系列(二):JVM内存结构

原文出处:纯洁的微笑 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问题就会变的非常常见,了解JVM内存也是为了服务器出现性能问题的时候可以快速的了解那块的内存区域出现问题,以便于快速的解决生产故障. 先看一张图,这张图能很清晰的说明JVM内存结构布局. JVM内存结构主要有三大块:堆内存.方法区和栈.堆内存是JVM中最大的一块由年轻代和老年代组