上篇讲了jstack命令的使用,不知你是否和小编有一样的想法:我们能否自己写代码来实时监控线程堆栈信息呢?本篇我们将讲一下如何在我们的程序中模拟jstack获取线程堆栈信息。
一、 jar包准备
在我们安装完jdk后,里面就有我们的工具包,也许你从没使用过,今天就到了发挥他们用处的时候了!!!
jstack有两种实现方式,一种是基于attach api,其实现可以在tools.jar里找到;另一种是基于SA的实现,它被放在了sa-jdi.jar里。如果你通过idea搜索Jstack类,你会看到tools.jar和sa-jdi.jar各有一个Jstack类。
二、代码实战
上篇我们了解到要查看线程堆栈信息,首先要拿到虚拟机实例的PID,下面就是拿到PID的代码。
/**
* @title: jvmPid
* @description: 获取当前虚拟机实例运行PID
* @return int 虚拟机实例运行PID
*/
public static final int jvmPid() {
try {
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
Field jvm = runtime.getClass().getDeclaredField("jvm");
jvm.setAccessible(true);
VMManagement mgmt = (VMManagement) jvm.get(runtime);
Method pidMethod = mgmt.getClass().getDeclaredMethod("getProcessId");
pidMethod.setAccessible(true);
int pid = (Integer) pidMethod.invoke(mgmt);
return pid;
} catch (Exception e) {
return -1;
}
}
拿到PID后我们就要开始获取到线程堆栈信息了,下面是获取堆栈信息的代码。
/**
*
* @title: getThreadDumpInfo
* @description: 日志输出线程堆栈信息
* @param pid
* @throws AttachNotSupportedException
* @throws IOException
*/
public static final void getThreadDumpInfo(int pid) throws AttachNotSupportedException, IOException {
VirtualMachine virtualMachine = VirtualMachine.attach(String.valueOf(pid));
HotSpotVirtualMachine hotSpotVirtualMachine = (HotSpotVirtualMachine) virtualMachine;
InputStream inputStream = hotSpotVirtualMachine.remoteDataDump(new String[] {});
byte[] buff = new byte[256];
int len;
StringBuffer stringBuffer = new StringBuffer();
do {
len = inputStream.read(buff);
if (len > 0) {
String respone = new String(buff, 0, len, "UTF-8");
stringBuffer.append(respone);
}
} while (len > 0);
logger.debug(stringBuffer.toString());
inputStream.close();
virtualMachine.detach();
}
以下为示例日志。
2019-08-02 16:47:58 [main] [ com.sunshine.vm.DeadLock ] [ 136 ] [ DEBUG ] VM-PID:[ 14744 ]
2019-08-02 16:47:58 [main] [ com.sunshine.vm.DeadLock ] [ 90 ] [ DEBUG ] 2019-08-02 16:47:58
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode):
"Thread-2" #12 prio=5 os_prio=0 tid=0x0000000014a4f000 nid=0x2424 waiting on condition [0x00000000154df000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.sunshine.vm.DeadLock.run(DeadLock.java:114)
- locked <0x00000000ffd39940> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:748)
"Thread-1" #11 prio=5 os_prio=0 tid=0x000000001499f000 nid=0x5ec waiting on condition [0x00000000153df000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.sunshine.vm.DeadLock.run(DeadLock.java:101)
- locked <0x00000000ffd39950> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00000000141f7800 nid=0x39d8 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000141f3800 nid=0x1f9c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000001320f000 nid=0x1628 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001320e800 nid=0x183c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000131b7000 nid=0x1c4c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000013198800 nid=0x2004 in Object.wait() [0x0000000013edf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000ffc08668> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x00000000ffc08668> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000030ed000 nid=0x39a4 in Object.wait() [0x0000000013ddf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000ffc00b88> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000ffc00b88> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"main" #1 prio=5 os_prio=0 tid=0x0000000002ffe000 nid=0x2204 runnable [0x0000000002f4e000]
java.lang.Thread.State: RUNNABLE
at sun.tools.attach.WindowsVirtualMachine.enqueue(Native Method)
at sun.tools.attach.WindowsVirtualMachine.execute(WindowsVirtualMachine.java:96)
at sun.tools.attach.HotSpotVirtualMachine.executeCommand(HotSpotVirtualMachine.java:261)
at sun.tools.attach.HotSpotVirtualMachine.remoteDataDump(HotSpotVirtualMachine.java:218)
at com.sunshine.vm.DeadLock.getThreadDumpInfo(DeadLock.java:78)
at com.sunshine.vm.DeadLock.main(DeadLock.java:137)
"VM Thread" os_prio=2 tid=0x0000000013176800 nid=0x3844 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000003016800 nid=0x39e0 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000003018800 nid=0x2868 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x000000001420d000 nid=0xeb8 waiting on condition
JNI global references: 31
这样我们就可以在我们自己的项目中来实时监控我们自己的线程堆栈信息了。文章到这里就结束了,如有错误,欢迎交流指正,小编继续查bug去了~