jstack笔记
遇到java程序跑不动怎么办,jstack是比较容易想到的一个工具,利用jstack来dump出一个线程堆栈快照,然后具体分析。
一般的堆栈大概是由下面的部分组成的:
"resin-22129" daemon prio=10 tid=0x00007fbe5c34e000 nid=0x4cb1 waiting on condition [0x00007fbe4ff7c000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:315)
at com.caucho.env.thread2.ResinThread2.park(ResinThread2.java:196)
at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:147)
at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118) "Timer-20" daemon prio=10 tid=0x00007fe3a4bfb800 nid=0x1a31 in Object.wait() [0x00007fe3a077a000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000006f0620ff0> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:552)
- locked <0x00000006f0620ff0> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:505)
"resin-22129"线程名称:如果使用 java.lang.Thread 类生成一个线程的时候,线程名称为 Thread-(数字) 的形式,这里是resin生成的线程;daemon线程类型:线程分为守护线程 (daemon) 和非守护线程 (non-daemon) 两种,通常都是守护线程;prio=10线程优先级:默认为5,数字越大优先级越高;tid=0x00007fbe5c34e000JVM线程的id:JVM内部线程的唯一标识,通过 java.lang.Thread.getId()获取,通常用自增的方式实现;nid=0x4cb1系统线程id:对应的系统线程id(Native Thread ID),可以通过 top 命令进行查看,现场id是十六进制的形式;waiting on condition系统线程状态:这里是系统的线程状态;[0x00007fbe4ff7c000]起始栈地址:线程堆栈调用的其实内存地址;java.lang.Thread.State: WAITING (parking)JVM线程状态:这里标明了线程在代码级别的状态。- 线程调用栈信息:下面就是当前线程调用的详细栈信息,用于代码的分析。堆栈信息应该从下向上解读,因为程序调用的顺序是从下向上的。
系统线程状态 (Native Thread Status)
系统线程有如下状态:
deadlock
死锁线程,一般指多个线程调用期间进入了相互资源占用,导致一直等待无法释放的情况。
runnable
一般指该线程正在执行状态中,该线程占用了资源,正在处理某个操作,如通过SQL语句查询数据库、对某个文件进行写入等。
blocked
线程正处于阻塞状态,指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。
waiting on condition
线程正处于等待资源或等待某个条件的发生,具体的原因需要结合下面堆栈信息进行分析。
(1)如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某种资源且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的读取,或者正在等待其他线程的执行等。
(2)如果发现有大量的线程都正处于这种状态,并且堆栈信息中得知正等待网络读写,这是因为网络阻塞导致线程无法执行,很有可能是一个网络瓶颈的征兆:
- 网络非常繁忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;
- 网络可能是空闲的,但由于路由或防火墙等原因,导致包无法正常到达;
所以一定要结合系统的一些性能观察工具进行综合分析,比如netstat统计单位时间的发送包的数量,看是否很明显超过了所在网络带宽的限制;观察CPU的利用率,看系统态的CPU时间是否明显大于用户态的CPU时间。这些都指向由于网络带宽所限导致的网络瓶颈。
(3)还有一种常见的情况是该线程在 sleep,等待 sleep 的时间到了,将被唤醒。
waiting for monitor entry 或 in Object.wait()
Moniter 是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者class的锁,每个对象都有,也仅有一个 Monitor。

从上图可以看出,每个Monitor在某个时刻只能被一个线程拥有,该线程就是 "Active Thread",而其他线程都是 "Waiting Thread",分别在两个队列 "Entry Set"和"Waint Set"里面等待。其中在 "Entry Set" 中等待的线程状态是 waiting for monitor entry,在 "Wait Set" 中等待的线程状态是 in Object.wait()。
(1)"Entry Set"里面的线程。
我们称被 synchronized 保护起来的代码段为临界区
当一个线程申请进入临界区时,它就进入了 "Entry Set" 队列中,这时候有两种可能性:
- 该Monitor不被其他线程拥有,"Entry Set"里面也没有其他等待的线程。本线程即成为相应类或者对象的Monitor的Owner,执行临界区里面的代码;此时在Thread Dump中显示线程处于 "Runnable" 状态。
- 该Monitor被其他线程拥有,本线程在 "Entry Set" 队列中等待。此时在Thread Dump中显示线程处于 "waiting for monity entry" 状态。
临界区的设置是为了保证其内部的代码执行的原子性和完整性,但因为临界区在任何时间只允许线程串行通过,这和我们使用多线程的初衷是相反的。如果在多线程程序中大量使用synchronized,或者不适当的使用它,会造成大量线程在临界区的入口等待,造成系统的性能大幅下降。如果在Thread Dump中发现这个情况,应该审视源码并对其进行改进。
(2)"Wait Set"里面的线程
当线程获得了Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(通常是被synchronized的对象)的wait()方法,放弃Monitor,进入 "Wait Set"队列。只有当别的线程在该对象上调用了 notify()或者notifyAll()方法,"Wait Set"队列中的线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。"Wait Set"中的线程在Thread Dump中显示的状态为 in Object.wait()。通常来说,
通常来说,当CPU很忙的时候关注 Runnable 状态的线程,反之则关注 waiting for monitor entry 状态的线程。
JVM线程运行状态 (JVM Thread Status)

在 java.lang.Thread.State 中定义了线程的状态:
NEW
至今尚未启动的线程的状态。线程刚被创建,但尚未启动。
RUNNABLE
可运行线程的线程状态。线程正在JVM中执行,有可能在等待操作系统中的其他资源,比如处理器。
BLOCKED
受阻塞并且正在等待监视器的某一线程的线程状态。处于受阻塞状态的某一线程正在等待监视器锁,以便进入一个同步的块/方法,或者在调用 Object.wait 之后再次进入同步的块/方法。
在Thread Dump日志中通常显示为 java.lang.Thread.State: BLOCKED (on object monitor) 。
WAITING
某一等待线程的线程状态。线程正在无期限地等待另一个线程来执行某一个特定的操作,线程因为调用下面的方法之一而处于等待状态:
- 不带超时的 Object.wait 方法,日志中显示为 java.lang.Thread.State: WAITING (on object monitor)
- 不带超时的 Thread.join 方法
- LockSupport.park 方法,日志中显示为 java.lang.Thread.State: WAITING (parking)
TIMED_WAITING
指定了等待时间的某一等待线程的线程状态。线程正在等待另一个线程来执行某一个特定的操作,并设定了指定等待的时间,线程因为调用下面的方法之一而处于定时等待状态:
- Thread.sleep 方法
- 指定超时值的 Object.wait 方法
- 指定超时值的 Thread.join 方法
- LockSupport.parkNanos
- LockSupport.parkUntil
TERMINATED
线程处于终止状态。
根据Java Doc中的说明,在给定的时间上,一个只能处于上述的一种状态之中,并且这些状态都是JVM的状态,跟操作系统中的线程状态无关。
参考
https://go-on.iteye.com/blog/1673894
http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html
https://www.javatang.com/archives/2017/10/25/36441958.html
https://www.cubrid.org/blog/the-principles-of-java-application-performance-tuning
jstack笔记的更多相关文章
- jstack实战死循环与死锁学习笔记
一.实战死循环导致CPU飙高 top -p pid -H jstack pid printf "%s" 十进制的线程id 二.创建CUP100%实例(死循环) 1.创建CpuCo ...
- 学习笔记: jstack与线程状态
jstatck可以打印JVM内部所有线程 1.查看有哪些java进程 2.查看所有线程的信息 重定向到5579.txt文件中 jstack 5579 > 5579.txt 3.线程的状态 New ...
- jstack 命令学习笔记
大部分内容转载自:Java命令学习系列(二)--Jstack jstack - 查看堆栈信息 jstack ( Stack Trace for java ) 命令主要作用就是为了查看堆栈信息.它可以用 ...
- Java系列笔记(4) - JVM监控与调优
目录 参数设置收集器搭配启动内存分配监控工具和方法调优方法调优实例 光说不练假把式,学习Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分析原因并解决之.通过学习,我觉得JVM ...
- Java性能调优笔记
Java性能调优笔记 调优步骤:衡量系统现状.设定调优目标.寻找性能瓶颈.性能调优.衡量是否到达目标(如果未到达目标,需重新寻找性能瓶颈).性能调优结束. 寻找性能瓶颈 性能瓶颈的表象:资源消耗过多. ...
- Twitter 新一代流处理利器——Heron 论文笔记之Heron架构
Twitter 新一代流处理利器--Heron 论文笔记之Heron架构 标签(空格分隔): Streaming-process realtime-process Heron Architecture ...
- Java并发编程的艺术读书笔记(1)-并发编程的挑战
title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...
- linux学习笔记2 - linux常用命令
转载请标注原链接:http://www.cnblogs.com/xczyd/p/5543731.html 第一篇博客:linux学习笔记1-ubuntu的安装与基本设置 之中,已经介绍了如何安装lin ...
- JDK自带JVM性能调优监控工具jps、jstack、jmap、jhat、jstat
原文地址:https://www.jianshu.com/p/db954cb968fb JVM性能调优监控工具jps.jstack.jmap.jhat.jstat位于JDK的bin目录,这些工具短小精 ...
随机推荐
- 08-可滚动Widget
可滚动Widget ViewPort视口 在Flutter中,术语ViewPort(视口),如无特别说明,则是指一个Widget的实际显示区域.例如,一个ListView的显示区域高度是800像素,虽 ...
- ubuntu下python在pycharm环境下安装setuptools和pip,和distutils.core
python安装好后,我们用pycharm安装所需的第三方模块时,出现“Python packaging tools not found. install packaging tools”点击安装输完 ...
- 20155202 实验四 Android开发基础
20155202 实验四 Android开发基础 实验内容 1.基于Android Studio开发简单的Android应用并部署测试; 2.了解Android.组件.布局管理器的使用: 3.掌握An ...
- 20155233刘高乐 第二周课堂实践以及MyOD
1. 除了main.c外,其他4个模块(add.c sub.c mul.c div.c)的源代码不想给别人,如何制作一个mymath.so共享库?main.c如何使用mymath.so? 2. 提交共 ...
- 第9周 实现PWD命令
第9周 实现PWD命令 码云链接:https://gitee.com/bestiisjava2017/laura5332/blob/master/%E4%BF%A1%E6%81%AF%E5%AE%89 ...
- CF 1025 D. Recovering BST
D. Recovering BST http://codeforces.com/contest/1025/problem/D 题意: 给出一个连续上升的序列a,两个点之间有边满足gcd(ai ,aj) ...
- set get方法诡异的空指针异常
发现原来是我的bean没有实例化 我的一直都是这么实例化的: UserEntity userEntity = null;难怪每次用不了set方法 原来是没有实例化 实例化之后就能正常使用了 UserE ...
- Android线程管理(一)——线程通信
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
- 创建oracle数据表示例sql
CREATE TABLE "BRAND_RELATION" ( "ID" NUMBER(10,0) NOT NULL ENABLE, ...
- Lua学习笔记(7): 模块
模块 模块就像是c语言工程项目目录里的.h.c文件或外部依赖项,为某一个文件的代码提供依赖,其实就是把工作分成几个模块,方便项目的管理,提高开发效率和维护效率 在Lua中,模块其实就是一个表,实现方式 ...