You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Spring DefaultLifecycleProcessor使用CountDownLatch?多线程场景存疑

关于Spring中CountDownLatch在SmartLifecycle停止逻辑里的作用及疑问解答

核心代码片段

顶层stop方法

public void stop() {
  .....
   CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
   .....
   try {
      latch.await(this.timeout, TimeUnit.MILLISECONDS);
     .......
}

doStop方法及说明

停止指定的Lifecycle Bean,确保所有依赖它的Bean先停止。
@param lifecycleBeans 键为Bean名称、值为Lifecycle实例的Map
@param beanName 要停止的Bean名称

private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
      final CountDownLatch latch, final Set<String> countDownBeanNames) {

      ......
      String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
      for (String dependentBean : dependentBeans) {
         doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
      }
      ......
     ((SmartLifecycle) bean).stop(() -> {
     latch.countDown();
     countDownBeanNames.remove(beanName);
     ......
   }
}

自定义SmartLifecycle Bean示例

@Component 
public class Stop1 implements SmartLifecycle { 
.....
@Override
public void stop() {
    System.err.println("0");
}
.....
public int getPhase() {
    return 1;
}
 }

@Component 
public class Stop2 implements SmartLifecycle { 
....
@Override
public void stop()  {
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.err.println("2");
}
......
public int getPhase() {
    return 1;
 }
}


@DependsOn("stop2") 
public class Stop3 implements SmartLifecycle { 
......
@Override
public void stop() {
    System.err.println("3");
}
.....
public int getPhase() {
    return 0;
}
}

问题解答

1. Spring为什么要用CountDownLatch?

核心是处理异步停止逻辑的等待问题:
SmartLifecycle的stop(Runnable callback)支持异步停止,回调会在Bean停止完成后才执行。如果不用CountDownLatch,主线程无法感知所有SmartLifecycle Bean的异步停止操作何时全部完成,可能导致Bean还没停干净,Spring就继续执行后续关闭流程,引发资源泄漏、数据不一致等问题。

CountDownLatch让主线程在latch.await()处阻塞,直到所有SmartLifecycle Bean完成停止并调用countDown(),计数器归0后才继续执行,保证所有该停的Bean都处理完毕。另外,CountDownLatch本身是线程安全的,多线程场景下无需额外加锁处理计数器的并发修改,避免了线程安全问题。

2. 多线程场景下会不会出现CountDownLatch提前归0、Spring提前关闭的情况?

不会,有两点关键保障:

  • 首先,doStop是递归调用的,会先处理当前Bean的所有依赖Bean的停止逻辑。比如你的例子里Stop3依赖Stop2,Spring会先递归调用doStop处理Stop2,再处理Stop3,确保依赖Bean的停止逻辑先被触发。
  • 其次,countDown()是在Bean停止完成的回调中执行的,不是调用stop()方法就立刻执行。比如Stop3的stop()方法里的逻辑全部执行完毕后,才会触发传入的Runnable执行latch.countDown()。也就是说,计数器减1的动作严格对应“Bean停止完成”这个节点。

哪怕是多线程场景,计数器归0时一定是所有SmartLifecycle Bean都已停止完毕,Spring不会提前关闭,CountDownLatch不会失效。


内容的提问来源于stack exchange,提问作者user16261266

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 16:20:23