深入研究Java线程Dump分析:掌握发现和解决多线程问题的关键技巧

news2024/11/19 1:50:40

1 Thread Dump介绍

1.1 什么是Thread Dump

Thread Dump是非常有用的诊断Java应用问题的工具。每一个Java虚拟机都有及时生成所有线程在某一点状态的thread-dump的能力,虽然各个 Java虚拟机打印的thread dump略有不同,但是大多都提供了当前活动线程的快照,及JVM中所有Java线程的堆栈跟踪信息,堆栈信息一般包含完整的类名及所执行的方法,如果可能的话还有源代码的行数。

1.2 Thread Dump特点



4de0bf39e27c701bb84d118cecff72d8.jpeg



1.3 Thread Dump抓取

一般当服务器挂起,崩溃或者性能低下时,就需要抓取服务器的线程堆栈(Thread Dump)用于后续的分析。在实际运行中,往往一次 dump的信息,还不足以确认问题。为了反映线程状态的动态变化,需要接连多次做thread dump,每次间隔10-20s,建议至少产生三次 dump信息,如果每次 dump都指向同一个问题,我们才确定问题的典型性。



1.操作系统命令获取ThreadDump



94bbff8388f0269b0f076a6219a5e39a.jpeg



注意:



e69f6df7805784155dfea5ba90005fa8.jpeg



2.JVM 自带的工具获取线程堆栈



9b213c3a8a102ff516ad45e5d7138039.jpeg



2.1 Thread Dump信息

1.头部信息:时间,JVM信息



11ea844d7ef400606cd5cac89750c2b9.jpeg



2.线程INFO信息块:



72d1a562fddaa27d84fc2254bb994aa4.jpeg



de00eeb08a0223e1e73ba1f912ec8831.jpeg



3.Java thread statck trace详解:



堆栈信息应该逆向解读:程序先执行的是第7行,然后是第6行,依次类推。



142dcadd568408d2b92a76bc88cd598b.jpeg



也就是说对象先上锁,锁住对象0xb3885f60,然后释放该对象锁,进入waiting状态。为啥会出现这样的情况呢?看看下面的java代码示例,就会明白:



5b34ed1f40fa45d49ca35386b53bb3f2.jpeg



408bdc737b86f36bc7a468deb9f600ee.jpeg



在堆栈的第一行信息中,进一步标明了线程在代码级的状态,例如:



ba531c6d6d9d06e83d63b9743c327864.jpeg



解释如下



e88457eae97736c2ae47e62bef2e1948.jpeg



2.2 Thread状态分析

线程的状态是一个很重要的东西,因此thread dump中会显示这些状态,通过对这些状态的分析,能够得出线程的运行状况,进而发现可能存在的问题。线程的状态在Thread.State这个枚举类型中定义



cf0ee6402e26c426e9df550df5ad7b13.jpeg



1.NEW



每一个线程,在堆内存中都有一个对应的Thread对象。Thread t = new Thread();当刚刚在堆内存中创建Thread对象,还没有调用t.start()方法之前,线程就处在NEW状态。在这个状态上,线程与普通的java对象没有什么区别,就仅仅是一个堆内存中的对象



2.RUNNABLE



该状态表示线程具备所有运行条件,在运行队列中准备操作系统的调度,或者正在运行。 这个状态的线程比较正常,但如果线程长时间停留在在这个状态就不正常了,这说明线程运行的时间很长(存在性能问题),或者是线程一直得不得执行的机会(存在线程饥饿的问题)。



3.BLOCKED



线程正在等待获取java对象的监视器(也叫内置锁),即线程正在等待进入由synchronized保护的方法或者代码块。synchronized用来保证原子性,任意时刻最多只能由一个线程进入该临界区域,其他线程只能排队等待。



4.WAITING



处在该线程的状态,正在等待某个事件的发生,只有特定的条件满足,才能获得执行机会。而产生这个特定的事件,通常都是另一个线程。也就是说,如果不发生特定的事件,那么处在该状态的线程一直等待,不能获取执行的机会。比如:



971c2d42eeeb09549a4427abd971c44b.jpeg



5.TIMED_WAITING



J.U.C中很多与线程相关类,都提供了限时版本和不限时版本的API。TIMED_WAITING意味着线程调用了限时版本的API,正在等待时间流逝。当等待时间过去后,线程一样可以恢复运行。如果线程进入了WAITING状态,一定要特定的事件发生才能恢复运行;而处在TIMED_WAITING的线程,如果特定的事件发生或者是时间流逝完毕,都会恢复运行



6.TERMINATED



线程执行完毕,执行完run方法正常返回,或者抛出了运行时异常而结束,线程都会停留在这个状态。这个时候线程只剩下Thread对象了,没有什么用了。



2.3 关键状态分析

1.Wait on conditionThe thread is either sleeping or waiting to be notified by another thread.



该状态说明它在等待另一个条件的发生,来把自己唤醒,或者干脆它是调用了 sleep(n)。



此时线程状态大致为以下几种:



4d10da6b86ff592dc57331815678f7f8.jpeg



2.Waiting for Monitor Entry 和 in Object.wait()The thread is waiting to get the lock for an object (some other thread may be holding the lock). This happens if two or more threads try to execute synchronized code. Note that the lock is always for an object and not for individual methods.



在多线程的JAVA程序中,实现线程之间的同步,就要说说 Monitor。Monitor是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者Class的锁。每一个对象都有,也仅有一个 Monitor。下面这个图,描述了线程和 Monitor之间关系,以及线程的状态转换图:



5d2a4d94753ce5881166cb3a5f14d58e.jpeg



如上图,每个Monitor在某个时刻,只能被一个线程拥有,该线程就是 “ActiveThread”,而其它线程都是 “Waiting Thread”,分别在两个队列“Entry Set”和“Wait Set”里等候。在“Entry Set”中等待的线程状态是“Waiting for monitor entry”,而在“Wait Set”中等待的线程状态是“in Object.wait()”。



先看“Entry Set”里面的线程。我们称为 synchronized保护起来的代码段为临界区。当一个线程申请进入临界区时,它就进入了“Entry Set”队列。对应的 code就像:



65dacc6bfafd13295c6459ef72726b6a.jpeg



这时有两种可能性:



377b5d8ea36615aca47dadc22704023a.jpeg



在第一种情况下,线程将处于 “Runnable”的状态,而第二种情况下,线程 DUMP会显示处于 “waiting for monitor entry”。如下:



fcd6b1709ad7939cc05931814d1f96ac.jpeg



临界区的设置,是为了保证其内部的代码执行的原子性和完整性。但是因为临界区在任何时间只允许线程串行通过,这和我们多线程的程序的初衷是相反的。如果在多线程的程序中,大量使用 synchronized,或者不适当的使用了它,会造成大量线程在临界区的入口等待,造成系统的性能大幅下降。如果在线程 DUMP中发现了这个情况,应该审查源码,改进程序。



再看“Wait Set”里面的线程。当线程获得了 Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(一般就是被 synchronized 的对象)的 wait() 方法,放弃 Monitor,进入 “Wait Set”队列。只有当别的线程在该对象上调用了 notify() 或者 notifyAll(),“Wait Set”队列中线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。在 “Wait Set”中的线程, DUMP中表现为: in Object.wait()。如下:



9bda80334940ac4297de446848fb0af4.jpeg



综上,一般CPU很忙时,则关注runnable的线程,CPU很闲时,则关注waiting for monitor entry的线程。



3.JDK 5.0 的 Lock



上面提到如果 synchronized和 monitor机制运用不当,可能会造成多线程程序的性能问题。在 JDK 5.0中,引入了 Lock机制,从而使开发者能更灵活的开发高性能的并发多线程程序,可以替代以往 JDK中的 synchronized和 Monitor的 机制。但是,要注意的是,因为 Lock类只是一个普通类,JVM无从得知 Lock对象的占用情况,所以在线程 DUMP中,也不会包含关于 Lock的信息, 关于死锁等问题,就不如用 synchronized的编程方式容易识别。



2.4 关键状态示例

显示BLOCKED状态



4050c467fd5bea67a72d51ff94778fb6.jpeg



先获取object的线程会执行5分钟,这5分钟内会一直持有object的监视器,另一个线程无法执行处在BLOCKED状态



7192c93ccf7a60fb12050b4761fca2c8.jpeg



通过thread dump可以看到:t2线程确实处在BLOCKED (on object monitor)。waiting for monitor entry 等待进入synchronized保护的区域



2.显示WAITING状态



5e40a7820f2516856c8b77639d204ff0.jpeg



6eb20aed446f47539969535ff3ac589f.jpeg



可以发现t1和t2都处在WAITING (on object monitor),进入等待状态的原因是调用了in Object.wait()。通过J.U.C包下的锁和条件队列,也是这个效果,大家可以自己实践下。



3.显示TIMED_WAITING状态



24ce58657f02e652abf432df2ed7c826.jpeg



95ca0e3ed4df41951a44e37740aaff32.jpeg



可以看到t1和t2线程都处在java.lang.Thread.State: TIMED_WAITING (parking),这个parking代表是调用的JUC下的工具类,而不是java默认的监视器

3.1 问题场景

1.CPU飙高,load高,响应很慢



a089b0231deba609f6b6be6ad843f61c.jpeg



2.查找占用CPU最多的线程



e3e7d676194987bfb4dcc9da86c3ac78.jpeg



3.CPU使用率不高但是响应很慢



be56c9579822a8d90f4ea1c5f553b6e4.jpeg



4.请求无法响应



e35140e46f6a1b1a394aed25e35375ce.jpeg



3.2死锁

死锁经常表现为程序的停顿,或者不再响应用户的请求。从操作系统上观察,对应进程的CPU占用率为零,很快会从top或prstat的输出中消失。



比如在下面这个示例中,是个较为典型的死锁情况:



3712a4804bc7600f86156351970657ed.jpeg



在 JAVA 5中加强了对死锁的检测。线程 Dump中可以直接报告出 Java级别的死锁,如下所示:



478483b5ed350558216755a675758b6d.jpeg



3.33热锁

热锁,也往往是导致系统性能瓶颈的主要因素。其表现特征为:由于多个线程对临界区,或者锁的竞争,可能出现:



7f4aeb80d1d3d2d23bddf9880b15cb6e.jpeg



上面的描述,都是一个 scalability(可扩展性)很差的系统的表现。从整体的性能指标看,由于线程热锁的存在,程序的响应时间会变长,吞吐量会降低。



那么,怎么去了解 “热锁 ”出现在什么地方呢



4f0c9cdf2a6a99ff03fdd52e58d63dff.jpeg



4. JVM重要线程

JVM运行过程中产生的一些比较重要的线程罗列如下:



07897330f26939615a26443fd2e174d6.jpeg

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

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

相关文章

“乘风而上,谋远共赢”润和软件HopeStage2023秋季渠道商会议圆满举行 润和软件 润和软件

10月18日,由江苏润和软件股份有限公司(以下简称“润和软件”)主办的HopeStage2023秋季渠道商会议圆满举行。本次会议以“乘风而上,谋远共赢”为主题,汇聚众多HopeStage渠道商与生态合作伙伴,共谋国产基础软…

怎么把本机设置成代理ip?

代理IP服务能帮助您隐藏您的真实IP,从而保护您的隐私和安全。本文将指导您如何将本机设置为代理IP。代理IP服务能帮助您隐藏您的真实IP,从而保护您的隐私和安全。本文将指导您如何将本机设置为代理IP。设置代理IP可以用于多种用途,比如&#…

进程相关内容(三)

目录 进程优先级 进程饥饿 Linux当中优先级标识符 优先级的修改参数NI 进程最终优先级 修改进程的优先级 操作系统实现优先级的方法 位图 并发的概念 进程切换原理 环境变量 其他环境变量 获得环境变量的方式 getenv系统调用函数 命令行参数 本地变量 export添加环境变量 unset…

修改echarts的tooltip样式 折线图如何配置阴影并实现渐变色和自适应

图片展示 一、引入echarts 这里不用多解释 vue里使用 import echarts from “echarts”; html页面引用js文件或用script标签引用 二、定义一个具有宽高的dom div <div id"echart-broken" style"width:400px;height: 200px;"></div>三、定义…

头歌平台——基于数组的工资处理系统

第1关&#xff1a;数据输入和计算 任务描述 本关任务&#xff1a; 编写函数input_data(char uid[10][5], int salary[10], int csalary[10], int revenue[10], int _water_electricity[10], int _deductions[10])&#xff0c;作用为输入职工的代号&#xff0c;岗位工资&#…

LabVIEW应用开发——控件的使用(二)

上篇介绍数值型控件和布尔型控件&#xff0c;这篇介绍字符串、路径控件、下拉框和数组控件。 LabVIEW应用开发——控件的使用&#xff08;一&#xff09; 1、字符串控件 实际应用中&#xff0c;字符串控件的显示很常用的&#xff0c;可用于显示串口信息、通讯交互信息、…

JAVA-记一次BigDecimal,String千分位转换

在显示类上面添加JsonSerialize注解&#xff0c;指定对应的转换格式例如&#xff0c;同理可在属性为BigDecimal的字段上添加注解&#xff0c;指定方法&#xff1a; private String userTypeStr;/*** 交易金额*/JsonSerialize(using StringSerialize.class)private String tran…

零基础制作电子期刊,不用担心不会设计排版

亲爱的朋友们&#xff0c;你是否想制作一本自己的电子期刊&#xff0c;但又担心不会设计排版&#xff1f;别担心&#xff01;今天我将教你如何零基础制作电子期刊&#xff0c;让你轻松上手&#xff01; 首先&#xff0c;你需要选择一个适合你的电子期刊模板。我们可以使用FLBOO…

智慧停车场项目-SpringBoot的Smart-parking

基于SpringBoot的Smart-parking 智慧停车场项目 介绍 基于 SpringBoot Vue 的智能停车场项目 系统首页 作者 如需本项目源代码&#xff0c;可扫码或者VX:zxd1534124905联系作者。 基础环境 JDK1.8、Maven、Mysql、IntelliJ IDEA、payCloud 相关组件 ok-adminvueiViewec…

文件批量管理:轻松复制备份并删除原文件

在日常生活和工作中&#xff0c;我们经常需要处理大量的文件。为了确保文件的安全性和完整性&#xff0c;您需要一种高效的文件批量管理方法。本文将向您介绍如何一一复制备份并删除原文件里的文件&#xff0c;让您的文件管理变得轻松便捷。 首先&#xff0c;我们要进入文件批…

Unity3D 基础——Coroutine 协同程序

Coroutine 称为协同程序或者协程&#xff0c;协同程序可以和主程序并行运行&#xff0c;和多线程有些类似。协同程序可以用来实现让一段程序等待一段时间后继续运行的效果。例如&#xff0c;执行步骤1&#xff0c;等待3秒&#xff1b;执行步骤2&#xff0c;等待某个条件为 true…

Web安全测试详解

前言 随着互联网时代的蓬勃发展&#xff0c;基于Web环境下的应用系统、应用软件也得到了越来越广泛的使用。 目前&#xff0c;很多企业的业务发展都依赖于互联网&#xff0c;比如&#xff0c;网上银行、网络购物、网络游戏等。但&#xff0c;由于很多恶意攻击者想通过截获他人…

狄克斯特拉(Dijkstra) 算法 php实现

《算法图解》中提到的狄克斯特拉算法&#xff0c;用php实现。 一 原理及解释 根据示例图求出起点到终点的最小耗费路径。 因为涉及每条路径的权重&#xff0c;所以这种算法仅适合有向路径。 所谓有向路径&#xff0c;指仅从起点指向终点的路径。 相对的无向路径&#xff0…

zookeeper(目前只有安装)

安装 流程 学kafka的时候安装 Apache ZooKeeper 安装地址&#xff1a;https://archive.apache.org/dist/zookeeper/zookeeper-3.5.7/apache-zookeeper-3.5.7-bin.tar.gz 解压 tar -zxvf kafka_2.12-3.0.0.tgz -C /export/server/ 改配置 cd config cp zoo_sample.cfg z…

Harbor 安装部署

Harbor基本介绍 1、Harbor 是 VMware 公司开源的企业级 Docker Registry 项目&#xff0c;Harbor 是一个企业级的 Docker 私有仓库项目。 2、Harbor以 Docker 公司开源的 Registry 为基础&#xff0c;提供了图形管理 UI 、基于角色的访问控制(Role Based AccessControl) 、AD/L…

cppcheck新手指引

文章目录 一、简介功能原理特征 二、安装WindowsLinux 三、使用1、Manual2、Windows gui3、Windows Cli、Linux4、vscode5、严重等级6、常用示例7、Suppressions8、html报告 四、用户是否可以编写检查规则&#xff1f;五、Cppcheck Premium 一、简介 cppcheck 是一个开源的静态…

vue中echart-gl 3D地图纹理实例

1. 安装 npm install echarts npm install echarts-gl2. vue组件 html部分 <template><section class"chartapp"><div class"map-chart" ref"mapChart"></div></section> </template>JS引入 import * as…

MIPS64乘法器模拟实验

目录 忽略溢出的乘法器 溢出提示的乘法器 忽略溢出的乘法器 首先&#xff0c;我们得了解乘法器如何由加法器设计得到&#xff0c;此处&#xff0c;我们以32位乘法为例。 总共分为4步&#xff1a; 1. 测试乘数最低位是否为1&#xff0c;是则给乘积加上被乘数&#xff0…

Linux-Jconsole连接远程服务器

Jconsole连接远程服务器 一、修改jmxremote.password.template文件二、启动jar项目三、jconsole远程连接1、打开的你jconsole2、远程连接 一、修改jmxremote.password.template文件 进去你的/idk/jre/lib/management目录下可以看到jmxremote.password.template文件 修改jmxr…

“智能+”时代,深维智信如何借助阿里云打造AI内容生成系统

云布道师 前言&#xff1a; 随着数字经济的发展&#xff0c;线上数字化远程销售模式越来越成为一种主流&#xff0c;销售流程也演变为线上视频会议、线下拜访等多种方式的结合。根据 Gartner 报告&#xff0c;到 2025 年 60% 的 B2B 销售组织将从基于经验和直觉的销售转变为数…