13.7.深入理解jstack日志,线程的状态

2024-04-19 16:48

本文主要是介绍13.7.深入理解jstack日志,线程的状态,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

13.7.深入理解jstack日志

转自:https://blog.csdn.net/iteye_5603/article/details/82652200

在分析线上问题时常使用到jstack 命令将当时Java应用程序的线程堆栈dump出来。
面对jstack 日志,我们如何查看?

首先要清楚线程的状态
线程的状态有:new、runnable、running、waiting、timed_waiting、blocked、dead
线程状态变迁图:
在这里插入图片描述
各状态说明:
New: 当线程对象创建时存在的状态,此时线程不可能执行;
Runnable:当调用thread.start()后,线程变成为Runnable状态。只要得到CPU,就可以执行;
Running:线程正在执行;
Waiting:执行thread.join()或在锁对象调用obj.wait()等情况就会进该状态,表明线程正处于等待某个资源或条件发生来唤醒自己;
Timed_Waiting:执行Thread.sleep(long)、thread.join(long)或obj.wait(long)等就会进该状态,与Waiting的区别在于Timed_Waiting的等待有时间限制;
Blocked:如果进入同步方法或同步代码块,没有获取到锁,则会进入该状态。
Dead:线程执行完毕,或者抛出了未捕获的异常之后,会进入dead状态,表示该线程结束

其次,对于jstack日志,我们要着重关注如下关键信息
Deadlock:表示有死锁
Waiting on condition:等待某个资源或条件发生来唤醒自己。具体需要结合jstacktrace来分析,比如线程正在sleep,网络读写繁忙而等待
Blocked:阻塞Waiting on monitor entry:在等待获取锁
in Object.wait():获取锁后又执行obj.wait()放弃锁
对于Waiting on monitor entryin Object.wait()的详细描述:Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。从下图中可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列" Entry Set"和"Wait Set"里面等候。在"Entry Set"中等待的线程状态是"Waiting for monitor entry",而在"Wait Set"中等待的线程状态是"in Object.wait()"
在这里插入图片描述
最后通过示例来实践一下
示例一:描述Blocked 和 Waiting to lock
在这里插入图片描述
执行后程序输出:
Thread[main,5,main]
说明主线程先进入同步代码块,获取到thread2对象上的锁。
通过jstack输出结果:
在这里插入图片描述
先说明下日志格式:
"thread2"为线程名称,在平时创建线程或线程池时请务必取一个见明之义的线程名称,方便排查问题
prio=6:线程优先级,不用关心;
tid=0x0000000006540800:线程id,不用关心;
nid=0x2be4:操作系统映射的线程id, 非常关键,后面再使用jstack时补充。
waiting for monitor entry:表示线程正在等待获取锁
0x0000000006dbf000:线程栈起始地址

从jstack日志中,可以看到:主线程获取到thread2对象上的锁,因此正在执行sleep操作,状态为TIMED_WAINTING, 而thread2由于未获取到thread2对象上的锁,因此处于BLOCKED状态。
再细看,thread2 正在"waiting to lock <0x00000000d719d280>“,即试图在地址为0x00000000d719d280所在的对象获取锁,而该锁却被main线程占有(locked <0x00000000d719d280>)。main线程正在"waiting on condition”,说明正在等待某个条件触发,由jstacktrace来看,此线程正在sleep。
经验:如果在jstack日志发现大量的线程在waiting to lock 某个地址,只要能查到哪个线程获取到锁就可以方便定位问题了

示例二:描述waiting on condition
在这里插入图片描述
jstack日志输出结果:
在这里插入图片描述

从日志中可以看到,main线程的状态是Waiting,正在"waiting on condition"来唤醒自己。
结合jstackstrace日志来看,"parking to wait for <0x00000000d719ba70> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)"说明在调用ArrayBlockingQueue.put()阻塞了。

示例三:描述Object.wait()
在这里插入图片描述
程序输出结果:

Thread[thread2,5,main]
Thread[main,5,main]

说明线程thread2先进入同步代码块,获取到thread2对象上的锁。
jstack日志输出结果:
在这里插入图片描述
可以看出:线程thread2的状态是"Waiting", 正在"in Object.wait()"。表明该线程在获取到对象锁后,调用obj.wait()方法,放弃了锁,进入了"Wait Set"队列。

这篇关于13.7.深入理解jstack日志,线程的状态的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/918099

相关文章

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

Java发送SNMP至交换机获取交换机状态实现方式

《Java发送SNMP至交换机获取交换机状态实现方式》文章介绍使用SNMP4J库(2.7.0)通过RCF1213-MIB协议获取交换机单/多路状态,需开启SNMP支持,重点对比SNMPv1、v2c、v... 目录交换机协议SNMP库获取交换机单路状态获取交换机多路状态总结交换机协议这里使用的交换机协议为常

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

Java 日志中 Marker 的使用示例详解

《Java日志中Marker的使用示例详解》Marker是SLF4J(以及Logback、Log4j2)提供的一个接口,它本质上是一个命名对象,你可以把它想象成一个可以附加到日志语句上的标签或戳... 目录什么是Marker?为什么使用Markejavascriptr?1. 精细化的过滤2. 触发特定操作3

linux查找java项目日志查找报错信息方式

《linux查找java项目日志查找报错信息方式》日志查找定位步骤:进入项目,用tail-f实时跟踪日志,tail-n1000查看末尾1000行,grep搜索关键词或时间,vim内精准查找并高亮定位,... 目录日志查找定位在当前文件里找到报错消息总结日志查找定位1.cd 进入项目2.正常日志 和错误日

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s