Background:
jstack is used to generate a thread snapshot of the current time of the JVM. It can locate problems such as thread deadlock, dead cycle, thread pause caused by too long external request time.
Thread classification:
gc thread
Tomcat worker thread
Tomcat Boss thread (IO thread)
Dubbo
Netty
JIT thread [CompilerThread3]
User defined thread pool
Thread status:
WAITING
TIMED_WAITING
BLOCK
RUNNABLE
TERMANTED
Actual operation:
Usage 1: find threads with high CPU consumption (dead cycle)
1. Top - HP process ID to view the status of all threads in the process;
2. printf "%x\n" thread ID converts the thread ID with high CPU consumption to hexadecimal;
3. jstack -l process ID > log.txt;
Find the thread ID obtained in step 2 in log.txt and view the call stack.
"http-nio2-9386-exec-25" #52 daemon prio=5 os_prio=31 tid=0x00007ff9c46d6800 nid=0x7c03 waiting on condition [0x000070000a651000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007816cdbc8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039) at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:103) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:31) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748)
Usage 2: find deadlock
private Object lock1 = new Object(); private Object lock2 = new Object(); @RequestMapping("/deadlock") public String deadlock(){ Thread thread1 = new Thread(){ @Override public void run() { super.run(); synchronized (lock1){ LockSupport.parkNanos(1000000); synchronized (lock2){ } } } }; thread1.setName("yzy"); thread1.start(); Thread thread2 = new Thread(){ @Override public void run() { super.run(); synchronized (lock2){ LockSupport.parkNanos(1000000); synchronized (lock1){ } } } }; thread2.setName("yzk"); thread2.start(); return "OK"; }
Found one Java-level deadlock: ============================= "yzk": waiting to lock monitor 0x00007ff9c1803618 (object 0x0000000781c4e118, a java.lang.Object), which is held by "yzk" "yzk": waiting to lock monitor 0x00007ff9c18036c8 (object 0x0000000781c4e108, a java.lang.Object), which is held by "yzy" "yzy": waiting to lock monitor 0x00007ff9c1803618 (object 0x0000000781c4e118, a java.lang.Object), which is held by "yzk" Java stack information for the threads listed above: =================================================== "yzk": at com.kuaikan.data.horadric.backend.controller.PingController$2.run(PingController.java:48) - waiting to lock <0x0000000781c4e118> (a java.lang.Object) "yzk": at com.kuaikan.data.horadric.backend.controller.PingController$2.run(PingController.java:51) - waiting to lock <0x0000000781c4e108> (a java.lang.Object) - locked <0x0000000781c4e118> (a java.lang.Object) "yzy": at com.kuaikan.data.horadric.backend.controller.PingController$1.run(PingController.java:36) - waiting to lock <0x0000000781c4e118> (a java.lang.Object) - locked <0x0000000781c4e108> (a java.lang.Object)
Best practices:
Both Thread and ThreadPool need to define a name
in addition to:
jstat -gc,jmap -dump:live,format=b,file=dump.hprof Some tools such as [pid] are used to analyze GC and memory leak, expecting to decompose next time.