java 线程休眠 假死,java多线程-jstack线程阻塞问题排查

线上高并发时,tomcat挂掉了,应用假死等问题,都可以使用jstack查看线程堆栈的问题。

jstack参数解说

首先线程状态如下:

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状态,表示该线程结束

b5f26daaad45b93410993b5b80f16321.png

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

Deadlock:表示有死锁

Waiting on condition:等待某个资源或条件发生来唤醒自己。比如线程正在sleep,网络读写繁忙而等待.

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

java.lang.Thread.State: WAITING (parking):一直等那个条件发生;

java.lang.Thread.State: TIMED_WAITING (parking或sleeping):定时的,那个条件不到来,也将定时唤醒自己。

Blocked:阻塞

Waiting on monitor entry:在等待获取锁,意味着它在等待进入一个临界区,所以它在”Entry Set“队列中等待,等待获取监视器。

in Object.wait():获取锁后又执行obj.wait()放弃锁,进入等待队列中。

sleeping:休眠的线程,调用了Thread.sleep()。

runnable:正在运行中。

注意: jstack表示的进程当前的状态哦。如果比如看到状态位RUNNABLE的,表示在你执行jstack时,该线程正在运行中。

对于Waiting on monitor entry 和 in Object.wait()的详细描述:Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。从下图中可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 "Running Thread",而其它线程都是 "Waiting Thread",分别在两个队列 " Entry Set"和 "Wait Set"里面等候。

在 "Entry Set"中等待的线程状态是:"Waiting for monitor entry",等待获取锁,在排队呢。

而在 "Wait Set"中等待的线程状态是 "in Object.wait()" 获取了锁,但是执行了wait()操作,线程被挂起,等待被唤醒,同样得重新获取锁。如下图的流转

8db4bfde23dfb17cdcc6d4ff1c603c78.png

大量某个状态

如果大量线程在“waiting for monitor entry”:

可能是一个全局锁阻塞住了大量线程。如果短时间内打印的thread dump文件反映,随着时间流逝,waiting for monitor entry 的线程越来越多,没有减少的趋势,可能意味着某些线程在临界区里呆的时间太长了,以至于越来越多新线程迟迟无法进入临界区。

如果大量线程在“waiting on condition”:

可能是获取第三方资源,尤其是第三方网络资源,迟迟获取不到Response,导致大量线程进入等待状态。

所以如果你发现有大量的线程都处在Wait on condition,从线程堆栈看,正等待网络读写,这可能是一个网络瓶颈的征兆,因为网络阻塞导致线程无法执行。

问题状态

Deadlock:表示有死锁

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

Blocked:阻塞

Waiting on monitor entry:在等待获取锁

虽然状态是这么多,但是具体问题还的具体查看,比如等待唤醒的资源,在下一次jstack查看时不存在了,就说明已经获取到锁并执行了。如果存在大量的,且长时间阻塞的那么就说明有很大问题了。

jstack其他参数说明

prio:线程的优先级

tid:线程id

nid:操作系统映射的线程id(16进制)

[0x0000000000000000] :后面末尾的数字,表示线程栈的起始地址。

基础操作

//查找进程号

> jps -lv |grep '应用名称' 或者ps -ef|grep '应用名称'

> jstack 3333 //进程号

top找到堆栈信息

> top //进入top后,shift+H查看线程

找到占用内存较大的线程id

> printf "%x\n" TID 将需要的线程ID转换为16进制格式 (16转10: printf %d\\n 0x5b7f)

> jstack [进程]|grep -A 10 [线程的16进制] //根据jstack找到该线程占用比较大的堆栈信息。

> jstack 13333 |grep -A 10 54f2

其他命令:

输出该进程拥有的线程总数

ps -mp 5841 -o THREAD,tid,time | wc -l

输出占用cpu最大的前10线程

ps -mp 5841 -o THREAD,tid,time | sort -rn | head -10

参考地址

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值