jstack
jstack 是一个Java命令行工具,用于打印Java应用程序的线程堆栈跟踪。它可以帮助开发者分析应用程序的线程状态,查找死锁或其他线程相关问题。
打印线程堆栈信息:jstack <PID>
2024-06-01 23:05:42
Full thread dump OpenJDK 64-Bit Server VM (17.0.2+8-86 mixed mode, sharing):
Threads class SMR info:
_java_thread_list=0x00000152f45f4780, length=15, elements={
0x00000152d9398f60, 0x00000152f37c0e10, 0x00000152f37c1c80, 0x00000152f37d9e00,
0x00000152f37db9c0, 0x00000152f37de480, 0x00000152f37dee30, 0x00000152f37dfbc0,
0x00000152f37e1990, 0x00000152f37e9cc0, 0x00000152f446e530, 0x00000152f4555430,
0x00000152f456bb90, 0x00000152f456e8a0, 0x00000152f37ab7b0
}
"main" #1 prio=5 os_prio=0 cpu=0.00ms elapsed=36.08s tid=0x00000152d9398f60 nid=0x8208 at breakpoint [0x00000027398ff000]
java.lang.Thread.State: RUNNABLE
at com.du.gc.YGCExample.main(YGCExample.java:22)
"Reference Handler" #2 daemon prio=10 os_prio=2 cpu=0.00ms elapsed=36.06s tid=0x00000152f37c0e10 nid=0x7a80 waiting on condition [0x0000002739fff000]
java.lang.Thread.State: RUNNABLE
at java.lang.ref.Reference.waitForReferencePendingList(java.base@17.0.2/Native Method)
at java.lang.ref.Reference.processPendingReferences(java.base@17.0.2/Reference.java:253)
at java.lang.ref.Reference$ReferenceHandler.run(java.base@17.0.2/Reference.java:215)
"Finalizer" #3 daemon prio=8 os_prio=1 cpu=0.00ms elapsed=36.06s tid=0x00000152f37c1c80 nid=0x7f48 in Object.wait() [0x000000273a0ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@17.0.2/Native Method)
- waiting on <0x00000000fff0d5c8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@17.0.2/ReferenceQueue.java:155)
- locked <0x00000000fff0d5c8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@17.0.2/ReferenceQueue.java:176)
at java.lang.ref.Finalizer$FinalizerThread.run(java.base@17.0.2/Finalizer.java:172)
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37d9e00 nid=0xaa60 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37db9c0 nid=0xa6e4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Service Thread" #6 daemon prio=9 os_prio=0 cpu=0.00ms elapsed=36.05s tid=0x00000152f37de480 nid=0xb090 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Monitor Deflation Thread" #7 daemon prio=9 os_prio=0 cpu=0.00ms elapsed=36.05s tid=0x00000152f37dee30 nid=0x8108 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #8 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37dfbc0 nid=0x6dc4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
No compile task
"C1 CompilerThread0" #16 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37e1990 nid=0x3e84 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
No compile task
"Sweeper thread" #20 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=36.05s tid=0x00000152f37e9cc0 nid=0xa21c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Common-Cleaner" #21 daemon prio=8 os_prio=1 cpu=0.00ms elapsed=36.01s tid=0x00000152f446e530 nid=0x52d0 in Object.wait() [0x000000273a8fe000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(java.base@17.0.2/Native Method)
- waiting on <0x00000000ffe39bc8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(java.base@17.0.2/ReferenceQueue.java:155)
- locked <0x00000000ffe39bc8> (a java.lang.ref.ReferenceQueue$Lock)
at jdk.internal.ref.CleanerImpl.run(java.base@17.0.2/CleanerImpl.java:140)
at java.lang.Thread.run(java.base@17.0.2/Thread.java:833)
at jdk.internal.misc.InnocuousThread.run(java.base@17.0.2/InnocuousThread.java:162)
"JDWP Transport Listener: dt_socket" #22 daemon prio=10 os_prio=0 cpu=0.00ms elapsed=35.99s tid=0x00000152f4555430 nid=0x72b4 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Event Helper Thread" #23 daemon prio=10 os_prio=0 cpu=0.00ms elapsed=35.99s tid=0x00000152f456bb90 nid=0x9f68 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Command Reader" #24 daemon prio=10 os_prio=0 cpu=0.00ms elapsed=35.99s tid=0x00000152f456e8a0 nid=0x3dd4 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Notification Thread" #25 daemon prio=9 os_prio=0 cpu=0.00ms elapsed=35.69s tid=0x00000152f37ab7b0 nid=0x49e0 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"VM Thread" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152f37ba200 nid=0xb7f8 runnable
"GC Thread#0" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152d93b9a40 nid=0x2658 runnable
"G1 Main Marker" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152d93bd9a0 nid=0x9ac8 runnable
"G1 Conc#0" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152d93be3b0 nid=0xac44 runnable
"G1 Refine#0" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152d944e5e0 nid=0x4778 runnable
"G1 Service" os_prio=2 cpu=0.00ms elapsed=36.07s tid=0x00000152f3684210 nid=0xb300 runnable
"VM Periodic Task Thread" os_prio=2 cpu=0.00ms elapsed=35.69s tid=0x00000152d93de9e0 nid=0xb750 waiting on condition
JNI global refs: 767, weak refs: 0
远程连接
jstack -l <hostname>:<port>
这里的 <hostname> 是远程服务器的地址,<port> 是JVM的JMX端口号,通常在启动Java应用时通过 -Dcom.sun.management.jmxremote.port=<port> 参数指定。
应用
- 死锁,Deadlock(重点关注)
- 等待资源,Waiting on condition(重点关注)
- 等待获取监视器,Waiting on monitor entry(重点关注)
- 阻塞,Blocked(重点关注)
- 执行中,Runnable
- 暂停,Suspended
- 对象等待中,Object.wait或TIMED_WAITING
- 停止,Parked
案例-死锁
死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉那它们都将无法推进下去
产生死锁主要原因
- 系统资源不足
- 进程运行推进的顺序不合适
- 资源分配不当
示例
public class DeadLockDemo {
static Object lockA = new Object();
static Object lockB = new Object();
public static void main(String[] args) {
Thread a = new Thread(() -> {
synchronized (lockA) {
System.out.println(Thread.currentThread().getName() + "\t" + " 自己持有A锁,期待获得B锁");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//锁b 已被其他线程持有
synchronized (lockB) {
System.out.println(Thread.currentThread().getName() + "\t 获得B锁成功");
}
}
}, "a");
a.start();
new Thread(() -> {
synchronized (lockB) {
System.out.println(Thread.currentThread().getName() + "\t" + " 自己持有B锁,期待获得A锁");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//锁A 已被其他线程持有
synchronized (lockA) {
System.out.println(Thread.currentThread().getName() + "\t 获得A锁成功");
}
}
}, "b").start();
}
}
try lock 避免死锁
public class TryLockDeadlock implements Runnable {
int flag = 1;
static Lock lock1 = new ReentrantLock();
static Lock lock2 = new ReentrantLock();
public static void main(String[] args) {
TryLockDeadlock r1 = new TryLockDeadlock();
TryLockDeadlock r2 = new TryLockDeadlock();
r1.flag = 0;
new Thread(r1).start();
new Thread(r2).start();
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (flag == 1) {
try {
if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) {
try {
System.out.println("线程1获取到了锁1");
Thread.sleep(new Random().nextInt(1000));
if (lock2.tryLock(800, TimeUnit.MILLISECONDS)) {
try {
System.out.println("线程1获取到了锁2");
System.out.println("线程1成功获取到了两把锁");
break;
} finally {
lock2.unlock();
}
} else {
System.out.println("线程1获取锁2失败,已重试");
}
} finally {
lock1.unlock();
Thread.sleep(new Random().nextInt(1000));
}
} else {
System.out.println("线程1获取锁1失败,已重试");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (flag == 0) {
try {
if (lock2.tryLock(3000, TimeUnit.MILLISECONDS)) {
try {
System.out.println("线程2获取到了锁2");
Thread.sleep(new Random().nextInt(1000));
if (lock1.tryLock(800, TimeUnit.MILLISECONDS)) {
try {
System.out.println("线程2获取到了锁1");
System.out.println("线程2成功获取到了两把锁");
break;
} finally {
lock1.unlock();
}
} else {
System.out.println("线程2获取锁1失败,已重试");
}
} finally {
lock2.unlock();
Thread.sleep(new Random().nextInt(1000));
}
} else {
System.out.println("线程2获取锁2失败,已重试");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
3. 排查
jps -l
死锁的类,进程号
jstack 进程编号
Found one Java-level deadlock:
=============================
"Thread-0":
waiting to lock monitor 0x00000218c5626e30 (object 0x0000000629237040, a java.lang.Object),
which is held by "Thread-1"
"Thread-1":
waiting to lock monitor 0x00000218c5625770 (object 0x0000000629237030, a java.lang.Object),
which is held by "Thread-0"
Java stack information for the threads listed above:
===================================================
"Thread-0":
at com.du.cpu.JstackDeadLockDemo.calLock_Obj1_First(JstackDeadLockDemo.java:36)
- waiting to lock <0x0000000629237040> (a java.lang.Object)
- locked <0x0000000629237030> (a java.lang.Object)
at com.du.cpu.JstackDeadLockDemo.lambda$testDeadlock$0(JstackDeadLockDemo.java:22)
at com.du.cpu.JstackDeadLockDemo$$Lambda$14/0x0000000800c01208.run(Unknown Source)
at java.lang.Thread.run(java.base@17.0.2/Thread.java:833)
"Thread-1":
at com.du.cpu.JstackDeadLockDemo.calLock_Obj2_First(JstackDeadLockDemo.java:49)
- waiting to lock <0x0000000629237030> (a java.lang.Object)
- locked <0x0000000629237040> (a java.lang.Object)
at com.du.cpu.JstackDeadLockDemo.lambda$testDeadlock$1(JstackDeadLockDemo.java:23)
at com.du.cpu.JstackDeadLockDemo$$Lambda$15/0x0000000800c01428.run(Unknown Source)
at java.lang.Thread.run(java.base@17.0.2/Thread.java:833)
Found 1 deadlock.