1.Jstack使用介绍

该命令打印java线程的堆栈跟踪,可以得知哪些线程被阻塞或正等待,以便于查找如线程死锁的原因

用法:

jstack [ option ] pid
jstack [ option ] executable core
jstack [ option ] [server-id@]remote-hostname-or-IP 

常用选项:

-F      当’jstack [-l] pid’没有相应的时候强制打印栈信息
-l      长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.
-m     打印java和native c/c++框架的所有栈信息.
常用参数:
core 将被打印信息的core dump文件
remote-hostname-or-IP 远程debug服务的主机名或ip
server-id 唯一id,假如一台主机上多个远程debug服务
id    需要被打印配置信息的java进程id,可以用jps查询

2.tomcat线程状态的种类

1.线程状态为“waiting on condition”
说明它在等待另一个条件的发生,来把自己唤醒,或者干脆它是调用了 sleep(N)。
此时线程状态大致为以下几种:
•java.lang.Thread.State: WAITING (parking):一直等那个条件发生;
•java.lang.Thread.State: TIMED_WAITING (parking或sleeping):定时的,那个条件不到来,也将定时唤醒自己。
如果大量线程在“waiting on condition”:
可能是它们又跑去获取第三方资源,尤其是第三方网络资源,迟迟获取不到Response,导致大量线程进入等待状态。
所以如果你发现有大量的线程都处在 Wait on condition,从线程堆栈看,正等待网络读写,这可能是一个网络瓶颈的征兆,因为网络阻塞导致线程无法执行。

实例1:定时的,那个条件不到来,也将定时唤醒自己。

"ContainerBackgroundProcessor[StandardEngine[Catalina]]" daemon prio=10 tid=0x00007f67a419a800 nid=0x4655 waiting on condition [0x00007f679a3fd000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1510)
        at java.lang.Thread.run(Thread.java:745)

实例2:一直等那个条件发生

"http-nio-8080-exec-1" daemon prio=10 tid=0x00007f677ca95800 nid=0x46a8 waiting on condition [0x00007f679a47e000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000007a0399b28> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
        at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
        at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104)
        at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)

1)“TIMED_WAITING (parking)”中的 timed_waiting 指等待状态,但这里指定了时间,到达指定的时间后自动退出等待状态;parking指线程处于挂起中。
2)“waiting on condition”需要与堆栈中的“parking to wait for <0x00000000acd84de8> (a java.util.concurrent.SynchronousQueue$TransferStack)” 结合来看。首先,本线程肯定是在等待某个条件的发生,来把自己唤醒。其次,SynchronousQueue 并不是一个队列,只是线程之间移交信息的机制,当我们把一个元素放入到 SynchronousQueue 中时必须有另一个线程正在等待接受移交的任务,因此这就是本线程在等待的条件

实例3

"RMI RenewClean-[10.24.189.110:1919]" daemon prio=10 tid=0x00007f6764ee1000 nid=0x4764 in Object.wait() [0x00007f67859b9000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
        - locked <0x00000007a1bca328> (a java.lang.ref.ReferenceQueue$Lock)
        at sun.rmi.transport.DGCClient$EndpointEntry$RenewCleanThread.run(DGCClient.java:535)
        at java.lang.Thread.run(Thread.java:745)

实例4

"Timer-8" daemon prio=10 tid=0x00007f676c032800 nid=0x5b7d in Object.wait() [0x00007f6785833000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.util.TimerThread.mainLoop(Timer.java:552)
        - locked <0x00000007b47c7630> (a java.util.TaskQueue)
        at java.util.TimerThread.run(Timer.java:505)

2.线程状态为“waiting for monitor entry”:
意味着它 在等待进入一个临界区 ,所以它在”Entry Set“队列中等待。
此时线程状态一般都是 Blocked:
java.lang.Thread.State: BLOCKED (on object monitor)

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

3.实例操作:

[root@tomcat01 conf]# jps

13886 Jps
21147 Application
13614 Bootstrap
[root@tomcat01 conf]# jstack 13614|grep "java.lang.Thread.State"|grep parking
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: TIMED_WAITING (parking)

[root@tomcat01 conf]# jstack 13614|grep "java.lang.Thread.State"|grep parking|wc -l
41
java.lang.Thread.State: WAITING (parking) 的数量等于minsparethread最小空闲的线程数的数值

检查 是否存在死锁
[root@VM_82_178_redhat ~]# jstack -l -F 7523

Attaching to process ID 7523, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.60-b23
Deadlock Detection:

**No deadlocks found**.