spring boot 全局异常处理无法直接捕获死锁异常,因为死锁是线程调度层面的阻塞状态,不会抛出 java 异常。要解决此问题,必须使用 threadmxbean 定期检测死锁线程,并在检测到后通过 applicationeventpublisher 发布自定义事件,由全局异常处理器拦截该事件并返回错误响应。

如何配置 ThreadMXBean 进行死锁检测
需要注入 ThreadMXBean 并编写定时任务来调用 findDeadlockedThreads() 方法。该方法会返回发生死锁的线程 ID 数组,若未发生死锁则返回 null。获取到线程 ID 后,需进一步查询线程名称和堆栈信息以便定位问题。
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class DeadlockDetector {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Scheduled(fixedRate = 5000)
public void checkDeadlocks() {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
if (deadlockedThreads != null) {
for (long threadId : deadlockedThreads) {
ThreadInfo info = threadMXBean.getThreadInfo(threadId);
eventPublisher.publishEvent(new DeadlockDetectedEvent(this, info));
}
}
}
}
上述代码每 5 秒执行一次检测。当检测到死锁时,它会获取线程详情并发布 DeadlockDetectedEvent。开发者需确保在启动类添加 @EnableScheduling 以启用定时任务。

如何实现全局异常处理器拦截死锁事件
创建一个自定义异常类 DeadlockException 和一个监听器或控制器来接收事件。在全局异常处理类中,可以针对该异常返回特定的 HTTP 状态码和消息。由于死锁通常涉及数据库连接池或分布式锁,建议返回 503 Service Unavailable 或 409 Conflict。
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(DeadlockException.class)
@ResponseStatus(HttpStatus.CONFLICT)
public String handleDeadlock(DeadlockException ex) {
return "Deadlock detected: " + ex.getMessage();
}
}
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class DeadlockEventListener {
@EventListener
public void handleDeadlockEvent(DeadlockDetectedEvent event) {
ThreadInfo info = event.getThreadInfo();
throw new DeadlockException("Deadlock found in thread: " + info.getThreadName());
}
}
注意:直接在监听器中抛出异常可能无法被 @RestControllerAdvice 捕获,因为监听器运行在独立线程中。更稳妥的方式是在监听器中记录日志并触发熔断或重启逻辑,或者将异常包装为业务异常并通过其他方式通知前端。但在纯 Spring MVC 环境下,若希望统一处理,可考虑将检测逻辑集成到拦截器或过滤器中,但这通常不适用于异步检测场景。此处展示的是标准的事件驱动模式,实际生产中常结合监控告警系统。

死锁检测频率对性能有何影响
频繁调用 findDeadlockedThreads() 会增加 CPU 开销,因为该方法需要遍历所有线程并检查锁状态。建议根据应用负载调整 @Scheduled 的频率,一般 5-10 秒一次即可满足大多数需求。对于高并发系统,可考虑仅在特定时间段或达到一定阈值时进行检测。











