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启动,调用
await()后立刻阻塞,打印“子线程1开始等待计数归零”。 - 主线程等待1秒后,打印“主线程正在处理其他任务”,随后启动子线程2。
- 子线程2执行
countDown(),计数归零,子线程1被唤醒,打印“子线程1等待结束,继续执行后续逻辑”。
简单总结:哪个线程调用await(),哪个线程就会被阻塞,直到计数归零;其他没有调用await()的线程可以正常执行自己的逻辑,不受影响。
内容的提问来源于stack exchange,提问作者usrmqj xv
相关产品推荐
相关产品推荐

