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

Java CountDownLatch未解锁:为何程序锁死且最后一行无法打印?

CountDownLatch 锁死问题分析与疑问解答

Hey there! Let's sort out your CountDownLatch issues one by one.

一、为什么你的程序会锁死?

先拆解下你的代码逻辑:

public static void main(String[] args) throws Exception{
    CountDownLatch countDownLatch = new CountDownLatch(1);
    countDownLatch.await(); // 主线程在这里直接阻塞
    new Thread(new Runnable() {
        @Override
        public void run() {
            countDownLatch.countDown();
            countDownLatch.countDown();
        }
    }).start();
    System.out.println("------should print-------");
}

问题核心出在执行顺序颠倒:

  • 主线程先调用了countDownLatch.await(),此时计数初始值是1,主线程直接进入阻塞状态,暂停执行后续所有代码。
  • 后面负责执行countDown()的线程根本没机会被启动,自然不会有任何操作让计数归零。
  • 没有线程触发计数归零的条件,主线程就会一直卡着,最后一行打印语句永远没机会输出。

修正后的代码

你需要把启动线程的代码放到await()之前,让子线程有机会执行countDown()来唤醒阻塞的线程:

public static void main(String[] args) throws Exception{
    CountDownLatch countDownLatch = new CountDownLatch(1);
    // 先启动子线程,让它准备好执行countDown操作
    new Thread(new Runnable() {
        @Override
        public void run() {
            countDownLatch.countDown();
            countDownLatch.countDown(); // 多调用一次也没关系,计数到0后再减不会改变状态
        }
    }).start();
    countDownLatch.await(); // 现在主线程阻塞,等待计数归零
    System.out.println("------should print-------");
}

这样子线程启动后会执行countDown(),把计数减到0(甚至负数,但CountDownLatch计数到0后状态就固定了),主线程的await()会被唤醒,顺利执行后续的打印语句。

二、如果await()在非主线程中调用,情况会怎样?

await()的本质作用是让当前调用它的线程进入阻塞状态,直到CountDownLatch的计数变为0——不管这个线程是主线程还是子线程,规则都是完全一致的。举个实际例子:

public static void main(String[] args) throws Exception{
    CountDownLatch countDownLatch = new CountDownLatch(1);

    // 子线程1调用await()进入阻塞
    new Thread(() -> {
        try {
            System.out.println("子线程1开始等待计数归零");
            countDownLatch.await();
            System.out.println("子线程1等待结束,继续执行后续逻辑");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();

    // 主线程先执行自己的逻辑,1秒后启动子线程2执行countDown
    Thread.sleep(1000);
    System.out.println("主线程正在处理其他任务");
    new Thread(() -> {
        System.out.println("子线程2执行countDown操作");
        countDownLatch.countDown();
    }).start();
}

这段代码的执行流程是:

  1. 子线程1启动,调用await()后立刻阻塞,打印“子线程1开始等待计数归零”。
  2. 主线程等待1秒后,打印“主线程正在处理其他任务”,随后启动子线程2。
  3. 子线程2执行countDown(),计数归零,子线程1被唤醒,打印“子线程1等待结束,继续执行后续逻辑”。

简单总结:哪个线程调用await(),哪个线程就会被阻塞,直到计数归零;其他没有调用await()的线程可以正常执行自己的逻辑,不受影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:24:10