Java Jvm中jstack日志的深入理解

堆栈日志分析,总结如下


jstack的日志,我们到底如何查看呢?

首先要弄清楚线程的状态

线程的状态有:

new、Runnable、running、waiting、timed_waiting、blocked、dead

线程状态变迁图


Java Jvm中jstack日志的深入理解


各状态说明:

New: 当线程对象创建时存在的状态,此时线程不可能执行。

Runnable:当调用thread.start()后,线程变成Runnable状态。只要得到CPU,就可以执行。

Running: 线程正在运行,就绪状态的线程获取了CPU,执行程序代码

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来分析,具体原因需结合stackstrace来分析。

  1. 一种情况是网络非常忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写
  2. 另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常到达.
  3. 如果堆栈信息明确是应用代码,则证明该线程正在等待资源. 一般是大量读取某资源,且该资源采用了资源锁的情况下,线程进入等待状态,等待资源的获取。
  4. 又或者,长在等待其他线程的执行等。
  5. 如果发现有大量的线程都在处在Wait On Condition,从线程statck看,正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。
  6. 另外一种出现Wait on condition的常见情况是该线程在sleep,等待sleep的时间到了时候将被唤醒。

Blocked: 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

Waiting on monitor entry: 在等待获取锁

in Object.wait(): 获取锁之后又执行obj.wait()放弃锁


对于 Waiting on monitor entry 和 in 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()”


举些例子

  1. blocked的例子


Java Jvm中jstack日志的深入理解

程序先输出main, 在输出thread, 说明main的线程是先获得同步锁的

执行jstack pid 输出信息如下:


Java Jvm中jstack日志的深入理解


Java Jvm中jstack日志的深入理解

可以看到thread1在进行等待获取到锁,此时进入waiting for monitor entry ,并是阻塞状态。

而main线程提前获取到锁,当由于调用了sleep此时进入到Timed_waiting状态,此时main线程锁住的对象地址是0x000000076bf4ef60,而thread1正在等待获取这个锁对象。


中间介绍几个参数指标

prio: 线程的优先级

tid: 线程id

nid: 操作系统映射的线程id,非常关键

0x000000002046f000 0x00000000029bf000 表示线程栈的起始地址。

从jstack日志中,可以看到:主线程获取到thread1对象上的锁,因为正在执行sleep操作,状态为TIMEE_WAITING,而thread1由于未获取到thread1对象上的锁,因为处于Blocked状态。

再细看,thread1 正在“waiting to lock <0x000000076bf4ef60>”,即试图在地址为<0x000000076bf4ef60>所在的对象上获取锁,而该锁确被main线程占有(locked <0x000000076bf4ef60>).

main线程正在“waiting on condition”,说明正在等待某个条件触发,由jstackstrace来看,此线程正在sleep.


总结:

如果在jstack日志发现大量的线程在waiting to lock某个地址,只要能查到哪个线程获取到锁就可以方便定位到问题了。


  1. object.wait()


Java Jvm中jstack日志的深入理解


执行后,查看jstack的日志如下


Java Jvm中jstack日志的深入理解


Java Jvm中jstack日志的深入理解

可以看到由于调用了object.wait()方法的时候放弃了锁,所以在thread2这个线程就出现了object.wait()状态,线程的状态就是waiting,等待notify来进行唤醒。

由于main线程在获取thread2的线程锁之后,调用了sleep方法,所以此时进入了waiting on condition等待某一个资源,进入到time_waiting状态。

  1. waiting on condition


Java Jvm中jstack日志的深入理解


Java Jvm中jstack日志的深入理解

来,一块看下执行结果,此时main线程进入了main on condition 状态,等待某一个资源,此时可以看到是在a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject 进行了等待,阻塞住了,这是由于put发生了阻塞。


总结

对于jstack日志,我们要着重关注如下关键信息

Deadlock: 表示有死锁。

Waiting on condition : 等待某个资源或条件发生时 来唤醒自己。 具体需要结果jstackspace 来分析,比如线程正在sleep,网络读写繁忙而等待

Blocked: 阻塞

Waiting on monitor entry: 在等待获取锁

如果说系统慢,那么就要特别关注 Blocked, Waiting on condition

如果说系统CPU耗的高,那么肯定是线程执行有无限循环,那么此时要关注系下Runnable状态。


谢谢大家,小小总结,望大家喜欢和关注~

展开阅读全文

页面更新:2024-04-27

标签:死锁   堆栈   日志   线程   例子   对象   状态   条件   关键   情况   地址   方法   资源   科技   网络   信息

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top