们可能在平时会用到jstack命令,进行线程状态查看,下面简单解读一下jstack中日志。
1示例代码
示例代码如下:
public class ReadStackLog {
public static void main(String[] args) throws JsonProcessingException {
new Thread(new TimeWaiting (), "TimeWaitingThread").start();
new Thread(new Waiting(), "WaitingThread").start();
// 使用两个Blocked线程,一个获取锁成功,另一个被阻塞
new Thread(new Blocked(), "BlockedThread-1").start();
new Thread(new Blocked(), "BlockedThread-2").start();
}
}
// 该线程不断地进行睡眠
class TimeWaiting implements Runnable {
@SneakyThrows
@Override
public void run() {
while (true) {
Thread.sleep(1000000);
}
}
}
// 该线程在Waiting.class实例上等待
class Waiting implements Runnable {
@Override
public void run() {
while (true) {
synchronized (Waiting.class) {
try {
Waiting.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
// 该线程在Blocked.class实例上加锁后,不会释放该锁
class Blocked implements Runnable {
@SneakyThrows
public void run() {
synchronized (Blocked.class) {
while (true) {
Thread.sleep(1000000);
}
}
}
}
复制代码
2运行日志查看
我们把程序运行起来,因为线程使用了sleep方法进行休眠,此时程序一直处于正在运行状态:
此时打开idea的Terminal面板,进行命令的输入,先输入jps查看线程的pid,再根据就stack pid查看到线程当前类所有栈信息的运行日志。
3逐个线程分析
我们摘取有用部分进行查看:
3.1 BlockedThread-2
"BlockedThread-2" #23 prio=5 os_prio=0 tid=0x0000000018f75800 nid=0xe9f0 waiting for monitor entry [0x000000001a67f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.juc.Blocked.run(ReadStackLog.java:45)
- waiting to lock <0x000000076bb165c0> (a java.lang.Class for com.juc.Blocked)
at java.lang.Thread.run(Thread.java:748)
复制代码
我们会发现BlockedThread-2这个线程状态是BLOCKED,并且下面提示正在等待Class类型的 Blocked.class锁释放(根据- waiting to lock提示信息得知),并且如果永远不释放,会造成一种死锁。
3.2 BlockedThread-1
"BlockedThread-1" #22 prio=5 os_prio=0 tid=0x0000000018f73800 nid=0xd59c waiting on condition [0x000000001a57e000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.juc.Blocked.run(ReadStackLog.java:45)
- locked <0x000000076bb165c0> (a java.lang.Class for com.juc.Blocked)
at java.lang.Thread.run(Thread.java:748)
复制代码
我们会发现BlockedThread-1这个线程状态是TIMED_WAITING,并且下面提示使用了Class类型的 Blocked.class锁(根据- lockerd提示信息得知),只不过目前进入了sleep方法,使线程休眠了。
3.3 WaitingThread
"WaitingThread" #21 prio=5 os_prio=0 tid=0x0000000018f71000 nid=0x6624 in Object.wait() [0x000000001a47f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076bb144a8> (a java.lang.Class for com.juc.Waiting)
at java.lang.Object.wait(Object.java:502)
at com.juc.Waiting.run(ReadStackLog.java:31)
- locked <0x000000076bb144a8> (a java.lang.Class for com.juc.Waiting)
at java.lang.Thread.run(Thread.java:748)
复制代码
同理我们得知,目前线程状态是WAITING状态,并且显示线程 in Object.wait() ,得知此线程调用了wait()方法,如果不唤醒,则永远等待。
3.4 TimeWaitingThread
"TimeWaitingThread" #20 prio=5 os_prio=0 tid=0x0000000018f6f000 nid=0xe8d0 waiting on condition [0x000000001a37f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.juc.TimeWaiting.run(ReadStackLog.java:20)
at java.lang.Thread.run(Thread.java:748)
复制代码
可以看出此线程状态是TIMED_WAITING,并且括号里显示了sleeping,说明此线程正在睡眠,等睡眠完成后,就会继续执行,并且此线程还没有任何锁信息。
3.5 其他线程
这里说明一下Finalizer线程
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000155c7800 nid=0xe14c in Object.wait() [0x000000001897e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076b588ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x000000076b588ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
复制代码
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001709d000 nid=0xdfc8 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
复制代码
只有进行垃圾收集的时候,才会被notify。 用到我们的 signal Dispatcher。
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000155bf800 nid=0xb88c in Object.wait() [0x000000001887e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076b586bf8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x000000076b586bf8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
复制代码
Reference Handler线程首先没有垃圾收集,不需要使用强弱引用。其次这个作为引用处理线程,目前我们的线程已经全部完成引用处理,此线程进入WAITING状态,除非加载新的类或者新的引用才会再次生效!
其他线程类似Monitor Ctrl-Break同理可得,不再赘述。