线程阻塞排除
例子
例如这种情况,假如java用@Scheduled 注解标识了一个定时任务,这定时任务会去调用第三方接口,有天这个第三方接口挂了,这里也没有做任何处理,相当于一直在等待第三方接口响应,导致其他定时任务无法调度,如果我不知道是这种情况的前提下我怎么排除呢
使用 jstack 或 VisualVM 检查线程状态
jstack:你可以通过 jstack 获取当前线程的堆栈信息。如果你怀疑某个线程(例如定时任务的线程)处于阻塞状态,可以通过 jstack 输出线程堆栈,查看是否有线程被 wait、block 或处于 BLOCKED 状态。
先使用jps获取pid,再用jstack分析
jstack <PID> > thread_dump.txt
通过分析堆栈信息,检查是否有定时任务的线程卡在等待外部接口的响应。如果是阻塞在网络调用上,堆栈中应该会显示类似 SocketInputStream.read() 或其他阻塞网络相关的栈帧。
案例
使用jstack查看到如下信息
我们可以看到线程卡在了 com.example.ExternalApiClient.callApi(ExternalApiClient.java:30) 这个代码行。这个信息直接告诉我们,在 ExternalApiClient 类的第 30 行调用了外部 API,但是由于某些原因(可能是网络问题或外部 API 延迟),该线程一直等待响应,没有释放。
"thirdPartyApiCaller" #18 prio=5 os_prio=0 tid=0x00007f07e32a4800 nid=0x1c14 waiting for I/O [0x00007f07e352d000]
java.lang.Thread.State: WAITING (on I/O)
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1055)
at sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:1130)
at com.example.ExternalApiClient.callApi(ExternalApiClient.java:30)
总结
使用