jstack的使用
2019-03-23 本文已影响0人
binecy
jstack命令主要打印指定Java进程的线程堆栈跟踪信息。它是一个很有用的命令。
检测死锁
编写一个导致死锁的简单栗子
public class DeadLockTest {
public static void main(String[] args) {
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();
ExecutorService service = Executors.newCachedThreadPool();
service.execute(() -> {
lock1.lock();
ThreadUtil.sleepIgnoreException(1000);
lock2.lock();
lock2.unlock();
lock1.unlock();
});
service.execute(() -> {
lock2.lock();
ThreadUtil.sleepIgnoreException(1000);
lock1.lock();
lock1.unlock();
lock2.unlock();
});
}
}
ThreadUtil.sleepIgnoreException可以sleep当前线程,并忽略InterruptedException异常,为了节省代码篇幅抽取了这个方法。
jps查看PID
$ jps
3876 DeadLockTest
通过jstack查看死锁信息
$ jstack 3876
...
Found one Java-level deadlock:
=============================
"pool-1-thread-2":
waiting for ownable synchronizer 0x00000000efa39c50, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by "pool-1-thread-1"
"pool-1-thread-1":
waiting for ownable synchronizer 0x00000000efa39c80, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by "pool-1-thread-2"
Java stack information for the threads listed above:
===================================================
"pool-1-thread-2":
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000efa39c50> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
at com.binecy.lock.DeadLockTest.lambda$main$1(DeadLockTest.java:33)
at com.binecy.lock.DeadLockTest$$Lambda$2/2074407503.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"pool-1-thread-1":
...
Found 1 deadlock.
可以通过堆栈信息查看发生死锁的代码位置。
分析占用CPU过高的线程
编写一个严重占用CPU的栗子
public class CpuHighTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
service.execute(()->{
int i = 0;
while (true)
i++;
});
service.execute(() -> {
int i = 0;
while (true) {
i++;
ThreadUtil.sleepIgnoreException(1000);
}
});
}
}
JPS查看PID
$ jps
4260 CpuHighTest
通过top -H -p 4260
查看(-H表示展示线程信息)
...
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4286 binecy 20 0 3350548 20124 4280 R 99.3 0.6 1:38.17 java
4260 binecy 20 0 3350548 20124 4280 S 0.0 0.6 0:00.00 java
...
PID为 4286 的线程严重占用cpu。
将PID 4286 转换为16进制 10be。
通过jstack查看对应的线程信息
$ jstack 4260
...
"pool-1-thread-1" #10 prio=5 os_prio=0 tid=0x00007fe4b026b000 nid=0x10be runnable [0x00007fe49cef1000]
java.lang.Thread.State: RUNNABLE
at com.binecy.lock.CpuHighTest.lambda$main$0(CpuHighTest.java:12)
at com.binecy.lock.CpuHighTest$$Lambda$1/558638686.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
nid=0x10be
这里就是上面的PID。
这里也可以通过堆栈信息找到对应的代码位置
参考:
如何使用jstack分析线程状态