countdownlatch 和 cyclicbarrier 不参与 spring bean 销毁流程,因其非 spring 管理的 bean 且未实现 disposablebean 或标注 @predestroy;若作为内部字段使用,需在 @predestroy 中手动调用 countdown() 或 reset() 清理。

CountDownLatch 和 CyclicBarrier 本身是 JDK 并发工具类,不参与 Spring Bean 的生命周期管理,**在 Bean 销毁阶段不会自动触发、也不被 Spring 框架识别或调用**。它们既不是 Spring 的回调接口(如 DisposableBean),也不受 @PreDestroy 或 destroy-method 等销毁扩展点影响。
为什么它们不出现在销毁阶段
Spring 的销毁逻辑只作用于容器中管理的单例 Bean,其触发依赖于:
- Bean 实现了
DisposableBean接口,且容器调用destroy() - Bean 方法标注了
@PreDestroy,由CommonAnnotationBeanPostProcessor处理 - XML 或
@Bean(destroyMethod = "...")显式配置了销毁方法
而 CountDownLatch 和 CyclicBarrier 是普通 Java 对象,若仅作为 Bean 内部字段存在(例如 service 类里 new 出来的一个 latch),Spring 完全不知道它的存在,更不会在销毁时干预其状态。
如果在 Bean 中持有并使用它们,销毁时需手动处理
虽然框架不接管,但开发者需自行判断是否需要清理或响应销毁事件。常见情况包括:
-
CountDownLatch 长期 await 未释放:若 Bean 销毁前有线程阻塞在
latch.await(),且计数器未归零,该线程将持续挂起——这不是内存泄漏,但可能造成资源滞留。建议在@PreDestroy中调用countDown()强制唤醒,或改用带超时的await(long, TimeUnit) -
CyclicBarrier 在等待中被弃用:若多个线程正阻塞在
barrier.await(),而 Bean 被销毁且屏障不再需要,应考虑调用reset()中断等待(注意:reset()会唤醒所有等待线程并抛出BrokenBarrierException) - 避免在销毁方法中调用 await:销毁方法应快速完成,不应引入阻塞逻辑;否则可能拖慢容器关闭,甚至导致上下文无法正常关闭
实际开发中的典型写法
以下是一个安全使用示例:
(Service 类中)@Service
public class DataSyncService {
private final CountDownLatch latch = new CountDownLatch(3);
@PostConstruct
public void init() {
// 启动子任务...
}
@PreDestroy
public void cleanup() {
// 主动释放,防止 await 悬停
latch.countDown();
latch.countDown();
latch.countDown();
// 或更稳妥地:latch = null; (配合 volatile/原子引用等确保可见性)
}
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











